Squashed 'third_party/allwpilib/' changes from 66b57f032..e473a00f9
e473a00f9 [wpiutil] Base64: Add unsigned span/vector variants (#3702)
52f2d580e [wpiutil] raw_uv_ostream: Add reset() (#3701)
d7b1e3576 [wpiutil] WebSocket: move std::function (#3700)
93799fbe9 [examples] Fix description of TrapezoidProfileSubsystem (#3699)
b84644740 [wpimath] Document pose estimator states, inputs, and outputs (#3698)
2dc35c139 [wpimath] Fix classpaths for JNI class loads (#3697)
2cb171f6f [docs] Set Doxygen extract_all to true and fix Doxygen failures (#3695)
a939cd9c8 [wpimath] Print uncontrollable/unobservable models in LQR and KF (#3694)
d5270d113 [wpimath] Clean up C++ StateSpaceUtil tests (#3692)
b20903960 [wpimath] Remove redundant discretization tests from StateSpaceUtilTest (#3689)
c0cb545b4 [wpilibc] Add deprecated Doxygen attribute to SpeedController (#3691)
35c9f66a7 [wpilib] Rename PneumaticsHub to PneumaticHub (#3686)
796d03d10 [wpiutil] Remove unused LLVM header (#3688)
8723caf78 [wpilibj] Make Java TrapezoidProfile.Constraints an immutable class (#3687)
187f50a34 [wpimath] Catch incorrect parameters to state-space models earlier (#3680)
8d04606c4 Replace instances of frc-characterization with SysId (NFC) (#3681)
b82d4f6e5 [hal, cscore, ntcore] Use WPI common handle type base
87e34967e [wpiutil] Add synchronization primitives
e32499c54 [wpiutil] Add ParallelTcpConnector (#3655)
aa0b49228 [wpilib] Remove redundant "quick turn" docs for curvature drive (NFC) (#3674)
57301a7f9 [hal] REVPH: Start closed-loop compressor control on init (#3673)
d1842ea8f [wpilib] Improve interrupt docs (NFC) (#3679)
558151061 [wpiutil] Add DsClient (#3654)
181723e57 Replace `.to<double>()` and `.template to<double>()` with `.value()` (#3667)
6bc1db44b [commands] Add pointer overload of AddRequirements (artf6003) (#3669)
737b57ed5 [wpimath] Update to drake v0.35.0 (#3665)
4d287d1ae [build] Upgrade WPIJREArtifact to JRE 2022-11.0.12u5 (#3666)
f26eb5ada [hal] Fix another typo (get -> gets) (NFC) (#3663)
94ed275ba [hal] Fix misspelling (numer -> number) (NFC) (#3662)
ac2f44da3 [wpiutil] uv: use move for std::function (#3653)
75fa1fbfb [wpiutil] json::serializer: Optimize construction (#3647)
5e689faea [wpiutil] Import MessagePack implementation (mpack) (#3650)
649a50b40 [wpiutil] Add LEB128 byte-by-byte reader (#3652)
e94397a97 [wpiutil] Move json_serializer.h to public headers (#3646)
4ec58724d [wpiutil] uv::Tcp: Clarify SetNoDelay documentation (#3649)
8cb294aa4 [wpiutil] WebSocket: Make Shutdown() public (#3651)
2b3a9a52b [wpiutil] json: Fix map iterator key() for std::string_view (#3645)
138cbb94b [wpiutil] uv::Async: Add direct call for no-parameter specialization (#3648)
e56d6dea8 [ci] Update testbench pool image to ubuntu-latest (#3643)
43f30e44e [build] Enable comments in doxygen source files (#3644)
9e6db17ef [build] Enable doxygen preprocessor expansion of WPI_DEPRECATED (#3642)
0e631ad2f Add WPILib version to issue template (#3641)
6229d8d2f [build] Docs: set case_sense_names to false (#3392)
4647d09b5 [docs] Fix Doxygen warnings, add CI docs lint job (#3639)
4ad3a5402 [hal] Fix PWM allocation channel (#3637)
05e5feac4 [docs] Fix brownout docs (NFC) (#3638)
67df469c5 [examples] Remove old command-based templates and examples (#3263)
689e9ccfb [hal, wpilib] Add brownout voltage configuration (#3632)
9cd4bc407 [docs] Add useLocal to avoid using installer artifacts (#3634)
61996c2bb [cscore] Fix Java direct callback notifications (#3631)
6d3dd99eb [build] Update to newest native-utils (#3633)
f0b484892 [wpiutil] Fix StringMap iterator equality check (#3629)
8352cbb7a Update development build instructions for 2022 (#3616)
6da08b71d [examples] Fix Intermediate Vision Java Example description (#3628)
5d99059bf [wpiutil] Remove optional.h (#3627)
fa41b106a [glass, wpiutil] Add missing format args (#3626)
4e3fd7d42 [build] Enable Zc:__cplusplus for Windows (#3625)
791d8354d [build] Suppress deprecation/removal warnings for old commands (#3618)
10f19e6fc [hal, wpilib] Add REV PneumaticsHub (#3600)
4c61a1305 [ntcore] Revert to per-element copy for toNative() (#3621)
7b3f62244 [wpiutil] SendableRegistry: Print exception stacktrace (#3620)
d347928e4 [hal] Use better error for when console out is enabled while attempting to use onboard serial port (#3622)
cc31079a1 [hal] Use setcap instead of setuid for setting thread priorities (#3613)
4676648b7 [wpimath] Upgrade to Drake v0.34.0 (#3607)
c7594c911 [build] Allow building wpilibc in cmake without cscore and opencv (#3605)
173cb7359 [wpilib] Add TimesliceRobot (#3502)
af295879f [hal] Set error status for I2C port out of range (#3603)
95dd20a15 [build] Enable spotbugs (#3601)
b65fce86b [wpilib] Remove Timer lock in wpilibj and update docs (#3602)
3b8d3bbcb Remove unused and add missing deprecated.h includes (#3599)
f9e976467 [examples] Rename DriveTrain classes to Drivetrain (#3594)
118a27be2 [wpilib] Add Timer tests (#3595)
59c89428e [wpilib] Deprecate Timer::HasPeriodPassed() (#3598)
202ca5e78 Force C++17 in .clang-format (#3597)
d6f185d8e Rename tests for consistency (#3592)
54ca474db [ci] Enable asan and tsan in CI for tests that pass (#3591)
1ca383b23 Add Debouncer (#3590)
179fde3a7 [build] Update to 2022 native utils and gradle 7 (#3588)
50198ffcf [examples] Add Mechanism2d visualization to Elevator Sim (#3587)
a446c2559 [examples] Synchronize C++ and Java Mechanism2d examples (#3589)
a7fb83103 [ci] clang-tidy: Generate compilation commands DB with Gradle (#3585)
4f5e0c9f8 [examples] Update ArmSimulation example to use Mechanism2d (#3572)
8164b91dc [CI] Print CMake test output on failure (#3583)
4d5fca27e [wpilib] Impove Mechanism2D documentation (NFC) (#3584)
fe59e4b9f Make C++ test names more consistent (#3586)
5c8868549 [wpilibc] Fix C++ MechanisimRoot2D to use same NT entries as Java/Glass (#3582)
9359431ba [wpimath] Clean up Eigen usage
72716f51c [wpimath] Upgrade to Eigen 3.4
382deef75 [wpimath] Explicitly export wpimath symbols
161e21173 [ntcore] Match standard handle layout, only allow 16 instances (#3577)
263a24811 [wpimath] Use jinja for codegen (#3574)
725251d29 [wpilib] Increase tolerances of DifferentialDriveSimTest (#3581)
4dff87301 [wpimath] Make LinearFilter::Factorial() constexpr (#3579)
60ede67ab [hal, wpilib] Switch PCM to be a single object that is allowed to be duplicated (#3475)
906bfc846 [build] Add CMake build support for sanitizers (#3576)
0d4f08ad9 [hal] Simplify string copy of joystick name (#3575)
a52bf87b7 [wpiutil] Add Java function package (#3570)
40c7645d6 [wpiutil] UidVector: Return old object from erase() (#3571)
5b886a23f [wpiutil] jni_util: Add size, operator[] to JArrayRef (#3569)
65797caa7 [sim] Fix halsim_ds_socket stringop overflow warning from GCC 10 (#3568)
66abb3988 [hal] Update runtime enum to allow selecting roborio 2 (#3565)
95a12e0ee [hal] UidSetter: Don't revert euid if its already current value (#3566)
27951442b [wpimath] Use external Eigen headers only (#3564)
c42e053ae [docs] Update to doxygen 1.9.2 (#3562)
e7048c8c8 [docs] Disable doxygen linking for common words that are also classes (#3563)
d8e0b6c97 [wpilibj] Fix java async interrupts (#3559)
5e6c34c61 Update to 2022 roborio image (#3537)
828f073eb [wpiutil] Fix uv::Buffer memory leaks caught by asan (#3555)
2dd5701ac [cscore] Fix mutex use-after-free in cscore test (#3557)
531439198 [ntcore] Fix NetworkTables memory leaks caught by asan (#3556)
3d9a4d585 [wpilibc] Fix AnalogTriggerOutput memory leak reported by asan (#3554)
54eda5928 [wpiutil] Ignore ubsan vptr upcast warning in SendableHelper moves (#3553)
5a4f75c9f [wpilib] Replace Speed controller comments with motor controller (NFC) (#3551)
7810f665f [wpiutil] Fix bug in uleb128 (#3540)
697e2dd33 [wpilib] Fix errant jaguar reference in comments (NFC) (#3550)
936c64ff5 [docs] Enable -linksource for javadocs (#3549)
1ea654954 [build] Upgrade CMake build to googletest 1.11.0 (#3548)
32d9949e4 [wpimath] Move controller tests to wpimath (#3541)
01ba56a8a [hal] Replace strncpy with memcpy (#3539)
e109c4251 [build] Rename makeSim flag to forceGazebo to better describe what it does (#3535)
e4c709164 [docs] Use a doxygen theme and add logo (#3533)
960b6e589 [wpimath] Fix Javadoc warning (#3532)
82eef8d5e [hal] Remove over current fault HAL functions from REV PDH (#3526)
aa3848b2c [wpimath] Move RobotDriveBase::ApplyDeadband() to MathUtil (#3529)
3b5d0d141 [wpimath] Add LinearFilter::BackwardFiniteDifference() (#3528)
c8fc715fe [wpimath] Upgrade drake files to v0.33.0 (#3531)
e5fe3a8e1 [build] Treat javadoc warnings as errors in CI and fix warnings (#3530)
e0c6cd3dc [wpimath] Add an operator for composing two Transform2ds (#3527)
2edd510ab [sim] Add sim wrappers for sensors that use SimDevice (#3517)
2b3e2ebc1 [hal] Fix HAL Notifier thread priority setting (#3522)
ab4cb5932 [gitignore] Update gitignore to ignore bazel / clion files (#3524)
57c8615af [build] Generate spotless patch on failure (#3523)
b90317321 Replace std::cout and std::cerr with fmt::print() (#3519)
10cc8b89c [hal] [wpilib] Add initial support for the REV PDH (#3503)
5d9ae3cdb [hal] Set HAL Notifier thread as RT by default (#3482)
192d251ee [wpilibcIntegrationTests] Properly disable DMA integration tests (#3514)
031962608 [wpilib] Add PS4Controller, remove Hand from GenericHID/XboxController (#3345)
25f6f478a [wpilib] Rename DriverStation::IsOperatorControl() to IsTeleop() (#3505)
e80f09f84 [wpilibj] Add unit tests (#3501)
c159f91f0 [wpilib] Only read DS control word once in IterativeRobotBase (#3504)
eb790a74d Add rio development docs documenting myRobot deploy tasks (#3508)
e47451f5a [wpimath] Replace auto with Eigen types (#3511)
252b8c83b Remove Java formatting from build task in CI (#3507)
09666ff29 Shorten Gazebo CI build (#3506)
baf2e501d Update myRobot to use 2021 java (#3509)
5ac60f0a2 [wpilib] Remove IterativeRobotBase mode init prints (#3500)
fb2ee8ec3 [wpilib] Add TimedRobot functions for running code on mode exit (#3499)
94e0db796 [wpilibc] Add more unit tests (#3494)
b25324695 [wpilibj] Add units to parameter names (NFC) (#3497)
1ac73a247 [hal] Rename PowerDistributionPanel to PowerDistribution (#3466)
2014115bc [examples] frisbeebot: Fix typo and reflow comments (NFC) (#3498)
4a944dc39 [examples] Consistently use 0 for controller port (#3496)
3838cc4ec Use unicode characters in docs equations (#3487)
85748f2e6 [examples] Add C++ TankDrive example (#3493)
d7b8aa56d [wpilibj] Rename DriverStation In[Mode] functions to follow style guide (#3488)
16e096cf8 [build] Fix CMake Windows CI (#3490)
50af74c38 [wpimath] Clean up NumericalIntegration and add Discretization tests (#3489)
bfc209b12 Automate fmt update (#3486)
e7f9331e4 [build] Update to Doxygen 1.9.1 (#3008)
ab8e8aa2a [wpimath] Update drake with upstream (#3484)
1ef826d1d [wpimath] Fix IOException path in WPIMath JNI (#3485)
52bddaa97 [wpimath] Disable iostream support for units and enable fmtlib (#3481)
e4dc3908b [wpiutil] Upgrade to fmtlib 8.0.1 (#3483)
1daadb812 [wpimath] Implement Dormand-Prince integration method (#3476)
9c2723391 [cscore] Add [[nodiscard]] to GrabFrame functions (#3479)
7a8796414 [wpilib] Add Notifier integration tests (#3480)
f8f13c536 [wpilibcExamples] Prefix decimal numbers with 0 (#3478)
1adb69c0f [ntcore] Use "NetworkTables" instead of "Network Tables" in NT specs (#3477)
5f5830b96 Upload wpiformat diff if one exists (#3474)
9fb4f35bb [wpimath] Add tests for DARE overload with Q, R, and N matrices (#3472)
c002e6f92 Run wpiformat (#3473)
c154e5262 [wpilib] Make solenoids exclusive use, PCM act like old sendable compressor (#3464)
6ddef1cca [hal] JNI setDIO: use a boolean and not a short (#3469)
9d68d9582 Remove extra newlines after open curly braces (NFC) (#3471)
a4233e1a1 [wpimath] Add script for updating Drake (#3470)
39373c6d2 Update README.md for new GCC version requirement (#3467)
d29acc90a [wpigui] Add option to reset UI on exit (#3463)
a371235b0 [ntcore] Fix dangling pointer in logger (#3465)
53b4891a5 [wpilibcintegrationtests] Fix deprecated Preferences usage (#3461)
646ded912 [wpimath] Remove incorrect discretization in pose estimators (#3460)
ea0b8f48e Fix some deprecation warnings due to fmtlib upgrade (#3459)
2067d7e30 [wpilibjexamples] Add wpimathjni, wpiutiljni to library path (#3455)
866571ab4 [wpiutil] Upgrade to fmtlib 8.0.0 (#3457)
4e1fa0308 [build] Skip PDB copy on windows build servers (#3458)
b45572167 [build] Change CI back to 18.04 docker images (#3456)
57a160f1b [wpilibc] Fix LiveWindow deprecation warning in RobotBase skeleton template (#3454)
29ae8640d [HLT] Implement duty cycle cross connect tests (#3453)
ee6377e54 [HLT] Add relay and analog cross connects (#3452)
b0f1ae7ea [build] CMake: Build the HAL even if WITH_CSCORE=OFF (#3449)
7aae2b72d Replace std::to_string() with fmt::format() (#3451)
73fcbbd74 [HLT] Add relay digital cross connect tests (#3450)
e7bedde83 [HLT] Add PWM tests that use DMA as the back end (#3447)
7253edb1e [wpilibc] Timer: Fix deprecated warning (#3446)
efa28125c [wpilibc] Add message to RobotBase on how to read stacktrace (#3444)
9832fcfe1 [hal] Fix DIO direction getter (#3445)
49c71f9f2 [wpilibj] Clarify robot quit message (#3364)
791770cf6 [wpimath] Move controller from wpilibj to wpimath (#3439)
9ce9188ff [wpimath] Add ReportWarning to MathShared (#3441)
362066a9b [wpilib] Deprecate getInstance() in favor of static functions (#3440)
26ff9371d Initial commit of cross connect integration test project (#3434)
4a36f86c8 [hal] Add support for DMA to Java (#3158)
85144e47f [commands] Unbreak build (#3438)
b417d961e Split Sendable into NT and non-NT portions (#3432)
ef4ea84cb [commands] Change grouping decorator impl to flatten nested group structures (#3335)
b422665a3 [examples] Invert right side of drive subsystems (#3437)
186dadf14 [hal] Error if attempting to set DIO output on an input port (#3436)
04e64db94 Remove redundant C++ lambda parentheses (NFC) (#3433)
f60994ad2 [wpiutil] Rename Java package to edu.wpi.first.util (#3431)
cfa1ca96f [wpilibc] Make ShuffleboardValue non-copyable (#3430)
4d9ff7643 Fix documentation warnings generated by JavaDoc (NFC) (#3428)
9e1b7e046 [build] Fix clang-tidy and clang-format (#3429)
a77c6ff3a [build] Upgrade clang-format and clang-tidy (NFC) (#3422)
099fde97d [wpilib] Improve PDP comments (NFC) (#3427)
f8fc2463e [wpilibc, wpiutil] Clean up includes (NFC) (#3426)
e246b7884 [wpimath] Clean up member initialization in feedforward classes (#3425)
c1e128bd5 Disable frivolous PMD warnings and enable PMD in ntcore (#3419)
8284075ee Run "Lint and Format" CI job on push as well as pull request (#3412)
f7db09a12 [wpimath] Move C++ filters into filter folder to match Java (#3417)
f9c3d54bd [wpimath] Reset error covariance in pose estimator ResetPosition() (#3418)
0773f4033 [hal] Ensure HAL status variables are initialized to zero (#3421)
d068fb321 [build] Upgrade CI to use 20.04 docker images (#3420)
8d054c940 [wpiutil] Remove STLExtras.h
80f1d7921 [wpiutil] Split function_ref to a separate header
64f541325 Use wpi::span instead of wpi::ArrayRef across all libraries (#3414)
2abbbd9e7 [build] clang-tidy: Remove bugprone-exception-escape (#3415)
a5c471af7 [wpimath] Add LQR template specialization for 2x2 system
edd2f0232 [wpimath] Add DARE solver for Q, R, and N with LQR ctor overloads
b2c3b2dd8 Use std::string_view and fmtlib across all libraries (#3402)
4f1cecb8e [wpiutil] Remove Path.h (#3413)
b336eac34 [build] Publish halsim_ws_core to Maven
2a09f6fa4 [build] Also build sim modules as static libraries
0e702eb79 [hal] Add a unified PCM object (#3331)
dea841103 [wpimath] Add fmtlib formatter overloads for Eigen::Matrix and units (#3409)
82856cf81 [wpiutil] Improve wpi::circular_buffer iterators (#3410)
8aecda03e [wpilib] Fix a documentation typo (#3408)
5c817082a [wpilib] Remove InterruptableSensorBase and replace with interrupt classes (#2410)
15c521a7f [wpimath] Fix drivetrain system identification (#3406)
989de4a1b [build] Force all linker warnings to be fatal for rio builds (#3407)
d9eeb45b0 [wpilibc] Add units to Ultrasonic class API (#3403)
fe570e000 [wpiutil] Replace llvm filesystem with C++17 filesystem (#3401)
01dc0249d [wpimath] Move SlewRateLimiter from wpilib to wpimath (#3399)
93523d572 [wpilibc] Clean up integration tests (#3400)
4f7a4464d [wpiutil] Rewrite StringExtras for std::string_view (#3394)
e09293a15 [wpilibc] Transition C++ classes to units::second_t (#3396)
827b17a52 [build] Create run tasks for Glass and OutlineViewer (#3397)
a61037996 [wpiutil] Avoid MSVC warning on span include (#3393)
4e2c3051b [wpilibc] Use std::string_view instead of Twine (#3380)
50915cb7e [wpilibc] MotorSafety::GetDescription(): Return std::string (#3390)
f4e2d26d5 [wpilibc] Move NullDeleter from frc/Base.h to wpi/NullDeleter.h (#3387)
cb0051ae6 [wpilibc] SimDeviceSim: use fmtlib (#3389)
a238cec12 [wpiutil] Deprecate wpi::math constants in favor of wpi::numbers (#3383)
393bf23c0 [ntcore, cscore, wpiutil] Standardize template impl files on .inc extension (NFC) (#3124)
e7d9ba135 [sim] Disable flaky web server integration tests (#3388)
0a0003c11 [wpilibjExamples] Fix name of Java swerve drive pose estimator example (#3382)
7e1b27554 [wpilibc] Use default copies and moves when possible (#3381)
fb2a56e2d [wpilibc] Remove START_ROBOT_CLASS macro (#3384)
84218bfb4 [wpilibc] Remove frc namespace shim (#3385)
dd7824340 [wpilibc] Remove C++ compiler version static asserts (#3386)
484cf9c0e [wpimath] Suppress the -Wmaybe-uninitialized warning in Eigen (#3378)
a04d1b4f9 [wpilibc] DriverStation: Remove ReportError and ReportWarning
831c10bdf [wpilibc] Errors: Use fmtlib
87603e400 [wpiutil] Import fmtlib (#3375)
442621672 [wpiutil] Add ArrayRef/std::span/wpi::span implicit conversions
bc15b953b [wpiutil] Add std::span implementation
6d20b1204 [wpiutil] StringRef, Twine, raw_ostream: Add std::string_view support (#3373)
2385c2a43 [wpilibc] Remove Utility.h (#3376)
87384ea68 [wpilib] Fix PIDController continuous range error calculations (#3170)
04dae799a [wpimath] Add SimpleMotorFeedforward::Calculate(velocity, nextVelocity) overload (#3183)
0768c3903 [wpilib] DifferentialDrive: Remove right side inversion (#3340)
8dd8d4d2d [wpimath] Fix redundant nested math package introduced by #3316 (#3368)
49b06beed [examples] Add Field2d to RamseteController example (#3371)
4c562a445 [wpimath] Fix typo in comment of update_eigen.py (#3369)
fdbbf1188 [wpimath] Add script for updating Eigen
f1e64b349 [wpimath] Move Eigen unsupported folder into eigeninclude
224f3a05c [sim] Fix build error when building with GCC 11.1 (#3361)
ff56d6861 [wpilibj] Fix SpeedController deprecated warnings (#3360)
1873fbefb [examples] Fix Swerve and Mecanum examples (#3359)
80b479e50 [examples] Fix SwerveBot example to use unique encoder ports (#3358)
1f7c9adee [wpilibjExamples] Fix pose estimator examples (#3356)
9ebc3b058 [outlineviewer] Change default size to 600x400 (#3353)
e21b443a4 [build] Gradle: Make C++ examples runnable (#3348)
da590120c [wpilibj] Add MotorController.setVoltage default (#3347)
561d53885 [build] Update opencv to 4.5.2, imgui/implot to latest (#3344)
44ad67ca8 [wpilibj] Preferences: Add missing Deprecated annotation (#3343)
3fe8fc75a [wpilibc] Revert "Return reference from GetInstance" (#3342)
3cc2da332 Merge branch '2022'
a3cd90dd7 [wpimath] Fix classpath used by generate_numbers.py (#3339)
d6cfdd3ba [wpilib] Preferences: Deprecate Put* in favor of Set* (#3337)
ba08baabb [wpimath] Update Drake DARE solver to v0.29.0 (#3336)
497b712f6 [wpilib] Make IterativeRobotBase::m_period private with getter
f00dfed7a [wpilib] Remove IterativeRobot base class
3c0846168 [hal] Use last error reporting instead of PARAMETER_OUT_OF_RANGE (#3328)
5ef2b4fdc [wpilibj] Fix @deprecated warning for SerialPort constructor (#3329)
23d2326d1 [hal] Report previous allocation location for indexed resource duplicates (#3322)
e338f9f19 [build] Fix wpilibc runCpp task (#3327)
c8ff626fe [wpimath] Move Java classes to edu.wpi.first.math (#3316)
4e424d51f [wpilibj] DifferentialDrivetrainSim: Rename constants to match the style guide (#3312)
6b50323b0 [cscore] Use Lock2DSize if possible for Windows USB cameras (#3326)
65c148536 [wpilibc] Fix "control reaches end of non-void function" warning (#3324)
f99f62bee [wpiutil] uv Handle: Use malloc/free instead of new/delete (#3325)
365f5449c [wpimath] Fix MecanumDriveKinematics (#3266)
ff52f207c [glass, wpilib] Rewrite Mechanism2d (#3281)
ee0eed143 [wpimath] Add DCMotor factory function for Romi motors (#3319)
512738072 [hal] Add HAL_GetLastError to enable better error messages from HAL calls (#3320)
ced654880 [glass, outlineviewer] Update Mac icons to macOS 11 style (#3313)
936d3b9f8 [templates] Add Java template for educational robot (#3309)
6e31230ad [examples] Fix odometry update in SwerveControllerCommand example (#3310)
05ebe9318 Merge branch 'main' into 2022
aaf24e255 [wpilib] Fix initial heading behavior in HolonomicDriveController (#3290)
8d961dfd2 [wpilibc] Remove ErrorBase (#3306)
659b37ef9 [wpiutil] StackTrace: Include offset on Linux (#3305)
0abf6c904 [wpilib] Move motor controllers to motorcontrol package (#3302)
4630191fa [wpiutil] circular_buffer: Use value initialization instead of passing zero (#3303)
b7b178f49 [wpilib] Remove Potentiometer interface
687066af3 [wpilib] Remove GyroBase
6b168ab0c [wpilib] Remove PIDController, PIDOutput, PIDSource
948625de9 [wpimath] Document conversion from filter cutoff frequency to time constant (#3299)
3848eb8b1 [wpilibc] Fix flywhel -> flywheel typo in FlywheelSim (#3298)
3abe0b9d4 [cscore] Move java package to edu.wpi.first.cscore (#3294)
d7fabe81f [wpilib] Remove RobotDrive (#3295)
1dc81669c [wpilib] Remove GearTooth (#3293)
01d0e1260 [wpilib] Revert move of RomiGyro into main wpilibc/j (#3296)
397e569aa [ntcore] Remove "using wpi" from nt namespace
79267f9e6 [ntcore] Remove NetworkTable -> nt::NetworkTable shim
48ebe5736 [ntcore] Remove deprecated Java interfaces and classes
c2064c78b [ntcore] Remove deprecated ITable interfaces
36608a283 [ntcore] Remove deprecated C++ APIs
a1c87e1e1 [glass] LogView: Add "copy to clipboard" button (#3274)
fa7240a50 [wpimath] Fix typo in quintic spline basis matrix
ffb4d38e2 [wpimath] Add derivation for spline basis matrices
f57c188f2 [wpilib] Add AnalogEncoder(int) ctor (#3273)
8471c4fb2 [wpilib] FieldObject2d: Add setTrajectory() method (#3277)
c97acd18e [glass] Field2d enhancements (#3234)
ffb590bfc [wpilib] Fix Compressor sendable properties (#3269)
6137f98eb [hal] Rename SimValueCallback2 to SimValueCallback (#3212)
a6f653969 [hal] Move registerSimPeriodic functions to HAL package (#3211)
10c038d9b [glass] Plot: Fix window creation after removal (#3264)
2d2eaa3ef [wpigui] Ensure window will be initially visible (#3256)
4d28b1f0c [wpimath] Use JNI for trajectory serialization (#3257)
3de800a60 [wpimath] TrajectoryUtil.h: Comment formatting (NFC) (#3262)
eff592377 [glass] Plot: Don't overwrite series ID (#3260)
a79faace1 [wpilibc] Return reference from GetInstance (#3247)
9550777b9 [wpilib] PWMSpeedController: Use PWM by composition (#3248)
c8521a3c3 [glass] Plot: Set reasonable default window size (#3261)
d71eb2cf3 [glass] Plot: Show full source name as tooltip and in popup (#3255)
160fb740f [hal] Use std::lround() instead of adding 0.5 and truncating (#3012)
48e9f3951 [wpilibj] Remove wpilibj package CameraServer (#3213)
8afa596fd [wpilib] Remove deprecated Sendable functions and SendableBase (#3210)
d3e45c297 [wpimath] Make C++ geometry classes immutable (#3249)
2c98939c1 [glass] StringChooser: Don't call SameLine() at end
a18a7409f [glass] NTStringChooser: Clear value of deleted entries
2f19cf452 [glass] NetworkTablesHelper: listen to delete events
da96707dc Merge branch 'main' into 2022
c3a8bdc24 [build] Fix clang-tidy action (#3246)
21624ef27 Add ImGui OutlineViewer (#3220)
1032c9b91 [wpiutil] Unbreak wpi::Format on Windows (#3242)
2e07902d7 [glass] NTField2D: Fix name lookup (#3233)
6e23e1840 [wpilibc] Remove WPILib.h (#3235)
3e22e4506 [wpilib] Make KoP drivetrain simulation weight 60 lbs (#3228)
79d1bd6c8 [glass] NetworkTablesSetting: Allow disable of server option (#3227)
fe341a16f [examples] Use more logical elevator setpoints in GearsBot (#3198)
62abf46b3 [glass] NetworkTablesSettings: Don't block GUI (#3226)
a95a5e0d9 [glass] Move NetworkTablesSettings to libglassnt (#3224)
d6f6ceaba [build] Run Spotless formatter (NFC) (#3221)
0922f8af5 [commands] CommandScheduler.requiring(): Note return can be null (NFC) (#2934)
6812302ff [examples] Make DriveDistanceOffboard example work in sim (#3199)
f3f86b8e7 [wpimath] Add pose estimator overload for vision + std dev measurement (#3200)
1a2680b9e [wpilibj] Change CommandBase.withName() to return CommandBase (#3209)
435bbb6a8 [command] RamseteCommand: Output 0 if interrupted (#3216)
3cf44e0a5 [hal] Add function for changing HAL Notifier thread priority (#3218)
40b367513 [wpimath] Units.java: Add kg-lb conversions (#3203)
9f563d584 [glass] NT: Fix return value in StringToDoubleArray (#3208)
af4adf537 [glass] Auto-size plots to fit window (#3193)
2560146da [sim] GUI: Add option to show prefix in Other Devices (#3186)
eae3a6397 gitignore: Ignore .cache directory (#3196)
959611420 [wpilib] Require non-zero positive value for PIDController.period (#3175)
9522f2e8c [wpimath] Add methods to concatenate trajectories (#3139)
e42a0b6cf [wpimath] Rotation2d comment formatting (NFC) (#3162)
d1c7032de [wpimath] Fix order of setting gyro offset in pose estimators (#3176)
d241bc81a [sim] Add DoubleSolenoidSim and SolenoidSim classes (#3177)
cb7f39afa [wpilibc] Add RobotController::GetBatteryVoltage() to C++ (#3179)
99b5ad9eb [wpilibj] Fix warnings that are not unused variables or deprecation (#3161)
c14b23775 [build] Fixup doxygen generated include dirs to match what users would need (#3154)
d447c7dc3 [sim] Add SimDeviceSim ctor overloads (#3134)
247420c9c [build] Remove jcenter repo (#3157)
04b112e00 [build] Include debug info in plugin published artifacts (#3149)
be0ce9900 [examples] Use PWMSparkMax instead of PWMVictorSPX (#3156)
69e8d0b65 [wpilib] Move RomiGyro into main wpilibc/j (#3143)
94e685e1b [wpimath] Add custom residual support to EKF (#3148)
5899f3dd2 [sim] GUI: Make keyboard settings loading more robust (#3167)
f82aa1d56 [wpilib] Fix HolonomicDriveController atReference() behavior (#3163)
fe5c2cf4b [wpimath] Remove ControllerUtil.java (#3169)
43d40c6e9 [wpiutil] Suppress unchecked cast in CombinedRuntimeLoader (#3155)
3d44d8f79 [wpimath] Fix argument order in UKF docs (NFC) (#3147)
ba6fe8ff2 [cscore] Add USB camera change event (#3123)
533725888 [build] Tweak OpenCV cmake search paths to work better on Linux (#3144)
29bf9d6ef [cscore] Add polled support to listener
483beb636 [ntcore] Move CallbackManager to wpiutil
fdaec7759 [examples] Instantiate m_ramseteController in example (#3142)
8494a5761 Rename default branch to main (#3140)
45590eea2 [wpigui] Hardcode window scale to 1 on macOS (#3135)
834a64920 [build] Publish libglass and libglassnt to Maven (#3127)
2c2ccb361 [wpimath] Fix Rotation2d equality operator (#3128)
fb5c8c39a [wpigui] clang-tidy: readability-braces-around-statements
f7d39193a [wpigui] Fix copyright in pfd and wpigui_metal.mm
aec796b21 [ntcore] Fix conditional jump on uninitialized value (#3125)
fb13bb239 [sim] GUI: Add right click popup for keyboard joystick settings (#3119)
c517ec677 [build] Update thirdparty-imgui to 1.79-2 (#3118)
e8cbf2a71 [wpimath] Fix typo in SwerveDrivePoseEstimator doc (NFC) (#3112)
e9c86df46 [wpimath] Add tests for swerve module optimization (#3100)
6ba8c289c [examples] Remove negative of ArcadeDrive(fwd, ..) in the C++ Getting Started Example (#3102)
3f1672e89 [hal] Add SimDevice createInt() and createLong() (#3110)
15be5cbf1 [examples] Fix segfault in GearsBot C++ example (#3111)
4cf0e5e6d Add quick links to API documentation in README (#3082)
6b1898f12 Fix RT priority docs (NFC) (#3098)
b3426e9c0 [wpimath] Fix missing whitespace in pose estimator doc (#3097)
38c1a1f3e [examples] Fix feildRelative -> fieldRelative typo in XControllerCommand examples (#3104)
4488e25f1 [glass] Shorten SmartDashboard window names (#3096)
cfdb3058e [wpilibj] Update SimDeviceSimTest (#3095)
64adff5fe [examples] Fix typo in ArcadeDrive constructor parameter name (#3092)
6efc58e3d [build] Fix issues with build on windows, deprecations, and native utils (#3090)
f393989a5 [wpimath, wpiutil] Add wpi::array for compile time size checking (#3087)
d6ed20c1e [build] Set macOS deployment target to 10.14 (#3088)
7c524014c [hal] Add [[nodiscard]] to HAL_WaitForNotifierAlarm() (#3085)
406d055f0 [wpilib] Fixup wouldHitLowerLimit in elevator and arm simulation classes. (#3076)
04a90b5dd [examples] Don't continually set setpoint in PotentiometerPID Examples (#3084)
8c5bfa013 [sim] GUI: Add max value setting for keyboard joysticks (#3083)
bc80c5535 [hal] Add SimValue reset() function (#3064)
9c3b51ca0 [wpilib] Document simulation APIs (#3079)
26584ff14 [wpimath] Add model description to LinearSystemId Javadocs (#3080)
42c3d5286 [examples] Sync Java and C++ trajectories in sim example (#3081)
64e72f710 [wpilibc] Add missing function RoboRioSim::ResetData (#3073)
e95503798 [wpimath] Add optimize() to SwerveModuleState (#3065)
fb99910c2 [hal] Add SimInt and SimLong wrappers for int/long SimValue (#3066)
e620bd4d3 [doc] Add machine-readable websocket specification (#3059)
a44e761d9 [glass] Add support for plot Y axis labels
ea1974d57 [wpigui] Update imgui and implot to latest
85a0bd43c [wpimath] Add RKF45 integration (#3047)
278e0f126 [glass] Use .controllable to set widgets' read-only state (#3035)
d8652cfd4 [wpimath] Make Java DCMotor API consistent with C++ and fix motor calcs (#3046)
377b7065a [build] Add toggleOffOn to Java spotless (#3053)
1e9c79c58 [sim] Use plant output to retrieve simulated position (#3043)
78147aa34 [sim] GUI: Fix Keyboard Joystick (#3052)
cd4a2265b [ntcore] Fix NetworkTableEntry::GetRaw() (#3051)
767ac1de1 [build] Use deploy key for doc publish (#3048)
d762215d1 [build] Add publish documentation script (#3040)
1fd09593c [examples] Add missing TestInit method to GettingStarted Example (#3039)
e45a0f6ce [examples] Add RomiGyro to the Romi Reference example (#3037)
94f852572 Update imaging link and fix typo (#3038)
d73cf64e5 [examples] Update RomiReference to match motor directions (#3036)
f945462ba Bump copyright year to 2021 (#3033)
b05946175 [wpimath] Catch Drake JNI exceptions and rethrow them (#3032)
62f0f8190 [wpimath] Deduplicate angle modulus functions (#2998)
bf8c0da4b [glass] Add "About" popup with version number (#3031)
dfdd6b389 [build] Increase Gradle heap size in Gazebo build (#3028)
f5e0fc3e9 Finish clang-tidy cleanups (#3003)
d741101fe [sim] Revert accidental commit of WSProvider_PDP.h (#3027)
e1620799c [examples] Add C++ RomiReference example (#2969)
749c7adb1 [command] Fix use-after-free in CommandScheduler (#3024)
921a73391 [sim] Add WS providers for AddressableLED, PCM, and Solenoid (#3026)
26d0004fe [build] Split Actions into different yml files (#3025)
948af6d5b [wpilib] PWMSpeedController.get(): Apply Inversion (#3016)
670a187a3 [wpilibc] SuppliedValueWidget.h: Forward declare ShuffleboardContainer (#3021)
be9f72502 [ntcore] NetworkTableValue: Use std::forward instead of std::move (#3022)
daf3f4cb1 [cscore] cscore_raw_cv.h: Fix error in PutFrame() (#3019)
5acda4cc7 [wpimath] ElevatorFeedforward.h: Add time.h include
8452af606 [wpimath] units/radiation.h: Add mass.h include
630d44952 [hal] ErrorsInternal.h: Add stdint.h include
7372cf7d9 [cscore] Windows NetworkUtil.cpp: Add missing include
b7e46c558 Include .h from .inc/.inl files (NFC) (#3017)
bf8f8710e [examples] Update Romi template and example (#2996)
6ffe5b775 [glass] Ensure NetworkTableTree parent context menu has an id (#3015)
be0805b85 [build] Update to WPILibVersioningPlugin 4.1.0 (#3014)
65b2359b2 [build] Add spotless for other files (#3007)
8651aa73e [examples] Enable NT Flush in Field2d examples (#3013)
78b542737 [build] Add Gazebo build to Actions CI (#3004)
fccf86532 [sim] DriverStationGui: Fix two bugs (#3010)
185741760 [sim] WSProvider_Joystick: Fix off-by-1 in incoming buttons (#3011)
ee7114a58 [glass] Add drive class widgets (#2975)
00fa91d0d [glass] Use ImGui style for gyro widget colors (#3009)
b7a25bfc3 ThirdPartyNotices: Add portable file dialogs license (#3005)
a2e46b9a1 [glass] modernize-use-nullptr (NFC) (#3006)
a751fa22d [build] Apply spotless for java formatting (#1768)
e563a0b7d [wpimath] Make LinearSystemLoop move-constructible and move-assignable (#2967)
49085ca94 [glass] Add context menus to remove and add NetworkTables values (#2979)
560a850a2 [glass] Add NetworkTables Log window (#2997)
66782e231 [sim] Create Left/Right drivetrain current accessors (#3001)
b60eb1544 clang-tidy: bugprone-virtual-near-miss
cbe59fa3b clang-tidy: google-explicit-constructor
c97c6dc06 clang-tidy: google-readability-casting (NFC)
32fa97d68 clang-tidy: modernize-use-nullptr (NFC)
aee460326 clang-tidy: modernize-pass-by-value
29c7da5f1 clang-tidy: modernize-make-unique
6131f4e32 clang-tidy: modernize-concat-nested-namespaces (NFC)
67e03e625 clang-tidy: modernize-use-equals-default
b124f9101 clang-tidy: modernize-use-default-member-init
d11a3a638 clang-tidy: modernize-use-override (NFC)
4cc0706b0 clang-tidy: modernize-use-using (NFC)
885f5a978 [wpilibc] Speed up ScopedTracerTest (#2999)
60b596457 [wpilibj] Fix typos (NFC) (#3000)
6e1919414 [build] Bring naming checkstyle rules up to date with Google Style guide (#1781)
8c8ec5e63 [wpilibj] Suppress unchecked cast warnings (#2995)
b8413ddd5 [wpiutil] Add noexcept to timestamp static functions (#2994)
5d976b6e1 [glass] Load NetworkTableView settings on first draw (#2993)
2b4317452 Replace NOLINT(runtime/explicit) comments with NOLINT (NFC) (#2992)
1c3011ba4 [glass] Fix handling of "/" NetworkTables key (#2991)
574a42f3b [hal] Fix UnsafeManipulateDIO status check (#2987)
9005cd59e [wpilib] Clamp input voltage in sim classes (#2955)
dd494d4ab [glass] NetworkTablesModel::Update(): Avoid use-after-move (#2988)
7cca469a1 [wpimath] NormalizeAngle: Make inline, remove unnamed namespace (#2986)
2aed432b4 Add braces to C++ single-line loops and conditionals (NFC) (#2973)
0291a3ff5 [wpiutil] StringRef: Add noexcept to several constructors (#2984)
5d7315280 [wpimath] Update UnitsTest.cpp copyright (#2985)
254931b9a [wpimath] Remove LinearSystem from LinearSystemLoop (#2968)
aa89744c9 Update OtherVersions.md to include wpimath info (#2983)
1cda3f5ad [glass] Fix styleguide (#2976)
8f1f64ffb Remove year from file copyright message (NFC) (#2972)
2bc0a7795 [examples] Fix wpiformat warning about utility include (#2971)
4204da6ad [glass] Add application icon
7ac39b10f [wpigui] Add icon support
6b567e006 [wpimath] Add support for varying vision standard deviations in pose estimators (#2956)
df299d6ed [wpimath] Add UnscentedKalmanFilter::Correct() overload (#2966)
4e34f0523 [examples] Use ADXRS450_GyroSim class in simulation example (#2964)
9962f6fd7 [wpilib] Give Field2d a default Sendable name (#2953)
f9d492f4b [sim] GUI: Show "Other Devices" window by default (#2961)
a8bb2ef1c [sim] Fix ADXRS450_GyroSim and DutyCycleEncoderSim (#2963)
240c629cd [sim] Try to guess "Map Gamepad" setting (#2960)
952567dd3 [wpilibc] Add missing move constructors and assignment operators (#2959)
10b396b4c [sim] Various WebSockets fixes and enhancements (#2952)
699bbe21a [examples] Fix comments in Gearsbot to match implementation (NFC) (#2957)
27b67deca [glass] Add more widgets (#2947)
581b7ec55 [wpilib] Add option to flush NetworkTables every iterative loop
acfbb1a44 [ntcore] DispatcherBase::Flush: Use wpi::Now()
d85a6d8fe [ntcore] Reduce limit on flush and update rate to 5 ms
20fbb5c63 [sim] Fix stringop truncation warning from GCC 10 (#2945)
1051a06a7 [glass] Show NT timestamps in seconds (#2944)
98dfc2620 [glass] Fix plots (#2943)
1ba0a2ced [sim] GUI: Add keyboard virtual joystick support (#2940)
4afb13f98 [examples] Replace M_PI with wpi::math::pi (#2938)
b27d33675 [examples] Enhance Romi templates (#2931)
00b9ae77f [sim] Change default WS port number to 3300 (#2932)
65219f309 [examples] Update Field2d position in periodic() (#2928)
f78d1d434 [sim] Process WS Encoder reset internally (#2927)
941edca59 [hal] Add Java SimDeviceDataJNI.getSimDeviceName (#2924)
a699435ed [wpilibj] Fix FlywheelSim argument order in constructor (#2922)
66d641718 [examples] Add tasks to run Java examples (#2920)
558e37c41 [examples] Add simple differential drive simulation example (#2918)
4f40d991e [glass] Switch name of Glass back to glass (#2919)
549af9900 [build] Update native-utils to 2021.0.6 (#2914)
b33693009 [glass] Change basename of glass to Glass (#2915)
c9a0edfb8 [glass] Package macOS application bundle
2c5668af4 [wpigui] Add platform-specific preferences save
751dea32a [wpilibc] Try to work around ABI break introduced in #2901 (#2917)
cd8f4bfb1 [build] Package up msvc runtime into maven artifact (#2913)
a6cfcc686 [wpilibc] Move SendableChooser Doxygen comments to header (NFC) (#2911)
b8c4f603d [wpimath] Upgrade to Eigen 3.3.9 (#2910)
0075e4b39 [wpilibj] Fix NPE in Field2d (#2909)
125af556c [simulation] Fix halsim_gui ntcore and wpiutil deps (#2908)
963ad5c25 [wpilib] Add noise to Differential Drive simulator (#2903)
387f56cb7 [examples] Add Romi reference Java example and templates (#2905)
b3deda38c [examples] Zero motors on disabledInit() in sim physics examples (#2906)
2a5ca7745 [glass] Add glass: an application for display of robot data
727940d84 [wpilib] Move Field2d to SmartDashboard
8cd42478e [wpilib] SendableBuilder: Make GetTable() visible
c11d34b26 [command] Use addCommands in command group templates (#2900)
339d7445b [sim] Add HAL hooks for simulationPeriodic (#2881)
d16f05f2c [wpilib] Fix SmartDashboard update order (#2896)
5427b32a4 [wpiutil] unique_function: Restrict implicit conversion (#2899)
f73701239 [ntcore] Add missing SetDefault initializer_list functions (#2898)
f5a6fc070 [sim] Add initialized flag for all solenoids on a PCM (#2897)
bdf5ba91a [wpilibj] Fix typo in ElevatorSim (#2895)
bc8f33877 [wpilib] Add pose estimators (#2867)
3413bfc06 [wpilib] PIDController: Recompute the error in AtSetpoint() (#2822)
2056f0ce0 [wpilib] Fix bugs in Hatchbot examples (#2893)
5eb8cfd69 [wpilibc] Fix MatchDataSender (#2892)
e6a425448 [build] Delete test folders after tests execute (#2891)
d478ad00d [imgui] Allow usage of imgui_stdlib (#2889)
53eda861d [build] Add unit-testing infrastructure to examples (#2863)
cc1d86ba6 [sim] Add title to simulator GUI window (#2888)
f0528f00e [build] CMake: Use project-specific binary and source dirs (#2886)
5cd2ad124 [wpilibc] Add Color::operator!= (#2887)
6c00e7a90 [build] CI CMake: build with GUI enabled (#2884)
53170bbb5 Update roboRIO toolchain installation instructions (#2883)
467258e05 [sim] GUI: Add option to not zero disconnected joysticks (#2876)
129be23c9 Clarify JDK installation instructions in readme (#2882)
8e9290e86 [build] Add separate CMake setting for wpimath (#2885)
7cf5bebf8 [wpilibj] Cache NT writes from DriverStation (#2780)
f7f9087fb [command] Fix timing issue in RamseteCommand (#2871)
256e7904f [wpilibj] SimDeviceSim: Fix sim value changed callback (#2880)
c8ea1b6c3 [wpilib] Add function to adjust LQR controller gain for pure time delay (#2878)
2816b06c0 [sim] HAL_GetControlWord: Fully zero output (#2873)
4c695ea08 Add toolchain installation instructions to README (#2875)
a14d51806 [wpimath] DCMotor: fix doc typo (NFC) (#2868)
017097791 [build] CMake: build sim extensions as shared libs (#2866)
f61726b5a [build] Fix cmake-config files (#2865)
fc27fdac5 [wpilibc] Cache NT values from driver station (#2768)
47c59859e [sim] Make SimDevice callbacks synchronous (#2861)
6e76ab9c0 [build] Turn on WITH_GUI for Windows cmake CI
5f78b7670 [build] Set GLFW_INSTALL to OFF
5e0808c84 [wpigui] Fix Windows cmake build
508f05a47 [imgui] Fix typo in Windows CMake target sources
Change-Id: I1737b45965f31803a96676bedc7dc40e337aa321
git-subtree-dir: third_party/allwpilib
git-subtree-split: e473a00f9785f9949e5ced30901baeaf426d2fc9
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java b/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java
index 2c08b17..e0db62e 100644
--- a/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java
+++ b/wpilibj/src/dev/java/edu/wpi/first/wpilibj/DevMain.java
@@ -1,20 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.HALUtil;
import edu.wpi.first.networktables.NetworkTablesJNI;
-import edu.wpi.first.wpiutil.RuntimeDetector;
+import edu.wpi.first.util.RuntimeDetector;
public final class DevMain {
- /**
- * Main entry point.
- */
+ /** Main entry point. */
public static void main(String[] args) {
System.out.println("Hello World!");
System.out.println(RuntimeDetector.getPlatformPath());
@@ -22,6 +17,5 @@
System.out.println(HALUtil.getHALRuntimeType());
}
- private DevMain() {
- }
+ private DevMain() {}
}
diff --git a/wpilibj/src/dev/native/cpp/main.cpp b/wpilibj/src/dev/native/cpp/main.cpp
index e324b44..a3e363e 100644
--- a/wpilibj/src/dev/native/cpp/main.cpp
+++ b/wpilibj/src/dev/native/cpp/main.cpp
@@ -1,8 +1,5 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// 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.
int main() {}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_I2C.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_I2C.java
index c31782c..29d3930 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_I2C.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_I2C.java
@@ -1,31 +1,26 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimEnum;
+import edu.wpi.first.networktables.NTSendable;
+import edu.wpi.first.networktables.NTSendableBuilder;
import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.util.sendable.SendableRegistry;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-/**
- * ADXL345 I2C Accelerometer.
- */
+/** ADXL345 I2C Accelerometer. */
@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"})
-public class ADXL345_I2C implements Accelerometer, Sendable, AutoCloseable {
+public class ADXL345_I2C implements Accelerometer, NTSendable, AutoCloseable {
private static final byte kAddress = 0x1D;
private static final byte kPowerCtlRegister = 0x2D;
private static final byte kDataFormatRegister = 0x31;
@@ -47,9 +42,7 @@
kY((byte) 0x02),
kZ((byte) 0x04);
- /**
- * The integer value representing this enumeration.
- */
+ /** The integer value representing this enumeration. */
@SuppressWarnings("MemberName")
public final byte value;
@@ -76,7 +69,7 @@
/**
* Constructs the ADXL345 Accelerometer with I2C address 0x1D.
*
- * @param port The I2C port the accelerometer is attached to
+ * @param port The I2C port the accelerometer is attached to
* @param range The range (+ or -) that the accelerometer will measure.
*/
public ADXL345_I2C(I2C.Port port, Range range) {
@@ -86,20 +79,26 @@
/**
* Constructs the ADXL345 Accelerometer over I2C.
*
- * @param port The I2C port the accelerometer is attached to
- * @param range The range (+ or -) that the accelerometer will measure.
+ * @param port The I2C port the accelerometer is attached to
+ * @param range The range (+ or -) that the accelerometer will measure.
* @param deviceAddress I2C address of the accelerometer (0x1D or 0x53)
*/
public ADXL345_I2C(I2C.Port port, Range range, int deviceAddress) {
m_i2c = new I2C(port, deviceAddress);
// simulation
- m_simDevice = SimDevice.create("ADXL345_I2C", port.value, deviceAddress);
+ m_simDevice = SimDevice.create("Accel:ADXL345_I2C", port.value, deviceAddress);
if (m_simDevice != null) {
- m_simRange = m_simDevice.createEnum("Range", true, new String[] {"2G", "4G", "8G", "16G"}, 0);
- m_simX = m_simDevice.createDouble("X Accel", false, 0.0);
- m_simY = m_simDevice.createDouble("Y Accel", false, 0.0);
- m_simZ = m_simDevice.createDouble("Z Accel", false, 0.0);
+ m_simRange =
+ m_simDevice.createEnumDouble(
+ "range",
+ SimDevice.Direction.kOutput,
+ new String[] {"2G", "4G", "8G", "16G"},
+ new double[] {2.0, 4.0, 8.0, 16.0},
+ 0);
+ m_simX = m_simDevice.createDouble("x", SimDevice.Direction.kInput, 0.0);
+ m_simY = m_simDevice.createDouble("y", SimDevice.Direction.kInput, 0.0);
+ m_simZ = m_simDevice.createDouble("z", SimDevice.Direction.kInput, 0.0);
}
// Turn on the measurements
@@ -111,6 +110,14 @@
SendableRegistry.addLW(this, "ADXL345_I2C", port.value);
}
+ public int getPort() {
+ return m_i2c.getPort();
+ }
+
+ public int getDeviceAddress() {
+ return m_i2c.getDeviceAddress();
+ }
+
@Override
public void close() {
SendableRegistry.remove(this);
@@ -217,16 +224,17 @@
}
@Override
- public void initSendable(SendableBuilder builder) {
+ public void initSendable(NTSendableBuilder builder) {
builder.setSmartDashboardType("3AxisAccelerometer");
NetworkTableEntry entryX = builder.getEntry("X");
NetworkTableEntry entryY = builder.getEntry("Y");
NetworkTableEntry entryZ = builder.getEntry("Z");
- builder.setUpdateTable(() -> {
- AllAxes data = getAccelerations();
- entryX.setDouble(data.XAxis);
- entryY.setDouble(data.YAxis);
- entryZ.setDouble(data.ZAxis);
- });
+ builder.setUpdateTable(
+ () -> {
+ AllAxes data = getAccelerations();
+ entryX.setDouble(data.XAxis);
+ entryY.setDouble(data.YAxis);
+ entryZ.setDouble(data.ZAxis);
+ });
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java
index 842ffd6..fa8b7d8 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL345_SPI.java
@@ -1,31 +1,26 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimEnum;
+import edu.wpi.first.networktables.NTSendable;
+import edu.wpi.first.networktables.NTSendableBuilder;
import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.util.sendable.SendableRegistry;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-/**
- * ADXL345 SPI Accelerometer.
- */
+/** ADXL345 SPI Accelerometer. */
@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"})
-public class ADXL345_SPI implements Accelerometer, Sendable, AutoCloseable {
+public class ADXL345_SPI implements Accelerometer, NTSendable, AutoCloseable {
private static final int kPowerCtlRegister = 0x2D;
private static final int kDataFormatRegister = 0x31;
private static final int kDataRegister = 0x32;
@@ -50,10 +45,7 @@
kY((byte) 0x02),
kZ((byte) 0x04);
- /**
- * The integer value representing this enumeration.
- */
- @SuppressWarnings("MemberName")
+ /** The integer value representing this enumeration. */
public final byte value;
Axes(byte value) {
@@ -79,23 +71,33 @@
/**
* Constructor.
*
- * @param port The SPI port that the accelerometer is connected to
+ * @param port The SPI port that the accelerometer is connected to
* @param range The range (+ or -) that the accelerometer will measure.
*/
public ADXL345_SPI(SPI.Port port, Range range) {
m_spi = new SPI(port);
// simulation
- m_simDevice = SimDevice.create("ADXL345_SPI", port.value);
+ m_simDevice = SimDevice.create("Accel:ADXL345_SPI", port.value);
if (m_simDevice != null) {
- m_simRange = m_simDevice.createEnum("Range", true, new String[] {"2G", "4G", "8G", "16G"}, 0);
- m_simX = m_simDevice.createDouble("X Accel", false, 0.0);
- m_simY = m_simDevice.createDouble("Y Accel", false, 0.0);
- m_simZ = m_simDevice.createDouble("Z Accel", false, 0.0);
+ m_simRange =
+ m_simDevice.createEnumDouble(
+ "range",
+ SimDevice.Direction.kOutput,
+ new String[] {"2G", "4G", "8G", "16G"},
+ new double[] {2.0, 4.0, 8.0, 16.0},
+ 0);
+ m_simX = m_simDevice.createDouble("x", SimDevice.Direction.kInput, 0.0);
+ m_simY = m_simDevice.createDouble("y", SimDevice.Direction.kInput, 0.0);
+ m_simZ = m_simDevice.createDouble("z", SimDevice.Direction.kInput, 0.0);
}
init(range);
SendableRegistry.addLW(this, "ADXL345_SPI", port.value);
}
+ public int getPort() {
+ return m_spi.getPort();
+ }
+
@Override
public void close() {
SendableRegistry.remove(this);
@@ -154,7 +156,7 @@
}
// Specify the data format to read
- byte[] commands = new byte[]{kDataFormatRegister, (byte) (kDataFormat_FullRes | value)};
+ byte[] commands = new byte[] {kDataFormatRegister, (byte) (kDataFormat_FullRes | value)};
m_spi.write(commands, commands.length);
if (m_simRange != null) {
@@ -194,8 +196,8 @@
return m_simZ.get();
}
ByteBuffer transferBuffer = ByteBuffer.allocate(3);
- transferBuffer.put(0,
- (byte) ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value));
+ transferBuffer.put(
+ 0, (byte) ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value));
m_spi.transaction(transferBuffer, transferBuffer, 3);
// Sensor is little endian
transferBuffer.order(ByteOrder.LITTLE_ENDIAN);
@@ -232,16 +234,17 @@
}
@Override
- public void initSendable(SendableBuilder builder) {
+ public void initSendable(NTSendableBuilder builder) {
builder.setSmartDashboardType("3AxisAccelerometer");
NetworkTableEntry entryX = builder.getEntry("X");
NetworkTableEntry entryY = builder.getEntry("Y");
NetworkTableEntry entryZ = builder.getEntry("Z");
- builder.setUpdateTable(() -> {
- AllAxes data = getAccelerations();
- entryX.setDouble(data.XAxis);
- entryY.setDouble(data.YAxis);
- entryZ.setDouble(data.ZAxis);
- });
+ builder.setUpdateTable(
+ () -> {
+ AllAxes data = getAccelerations();
+ entryX.setDouble(data.XAxis);
+ entryY.setDouble(data.YAxis);
+ entryZ.setDouble(data.ZAxis);
+ });
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java
index 340a776..2a9c2fe 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXL362.java
@@ -1,32 +1,28 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimEnum;
+import edu.wpi.first.networktables.NTSendable;
+import edu.wpi.first.networktables.NTSendableBuilder;
import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.util.sendable.SendableRegistry;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
/**
* ADXL362 SPI Accelerometer.
*
* <p>This class allows access to an Analog Devices ADXL362 3-axis accelerometer.
*/
-@SuppressWarnings("PMD.UnusedPrivateField")
-public class ADXL362 implements Accelerometer, Sendable, AutoCloseable {
+public class ADXL362 implements Accelerometer, NTSendable, AutoCloseable {
private static final byte kRegWrite = 0x0A;
private static final byte kRegRead = 0x0B;
@@ -41,7 +37,10 @@
private static final byte kFilterCtl_ODR_100Hz = 0x03;
private static final byte kPowerCtl_UltraLowNoise = 0x20;
+
+ @SuppressWarnings("PMD.UnusedPrivateField")
private static final byte kPowerCtl_AutoSleep = 0x04;
+
private static final byte kPowerCtl_Measure = 0x02;
public enum Axes {
@@ -49,7 +48,6 @@
kY((byte) 0x02),
kZ((byte) 0x04);
- @SuppressWarnings("MemberName")
public final byte value;
Axes(byte value) {
@@ -75,7 +73,7 @@
private double m_gsPerLSB;
/**
- * Constructor. Uses the onboard CS1.
+ * Constructor. Uses the onboard CS1.
*
* @param range The range (+ or -) that the accelerometer will measure.
*/
@@ -86,19 +84,25 @@
/**
* Constructor.
*
- * @param port The SPI port that the accelerometer is connected to
+ * @param port The SPI port that the accelerometer is connected to
* @param range The range (+ or -) that the accelerometer will measure.
*/
public ADXL362(SPI.Port port, Range range) {
m_spi = new SPI(port);
// simulation
- m_simDevice = SimDevice.create("ADXL362", port.value);
+ m_simDevice = SimDevice.create("Accel:ADXL362", port.value);
if (m_simDevice != null) {
- m_simRange = m_simDevice.createEnum("Range", true, new String[] {"2G", "4G", "8G", "16G"}, 0);
- m_simX = m_simDevice.createDouble("X Accel", false, 0.0);
- m_simY = m_simDevice.createDouble("Y Accel", false, 0.0);
- m_simZ = m_simDevice.createDouble("Z Accel", false, 0.0);
+ m_simRange =
+ m_simDevice.createEnumDouble(
+ "range",
+ SimDevice.Direction.kOutput,
+ new String[] {"2G", "4G", "8G", "16G"},
+ new double[] {2.0, 4.0, 8.0, 16.0},
+ 0);
+ m_simX = m_simDevice.createDouble("x", SimDevice.Direction.kInput, 0.0);
+ m_simY = m_simDevice.createDouble("y", SimDevice.Direction.kInput, 0.0);
+ m_simZ = m_simDevice.createDouble("z", SimDevice.Direction.kInput, 0.0);
}
m_spi.setClockRate(3000000);
@@ -133,6 +137,10 @@
SendableRegistry.addLW(this, "ADXL362", port.value);
}
+ public int getPort() {
+ return m_spi.getPort();
+ }
+
@Override
public void close() {
SendableRegistry.remove(this);
@@ -163,18 +171,17 @@
m_gsPerLSB = 0.002;
break;
case k8G:
- case k16G: // 16G not supported; treat as 8G
+ case k16G: // 16G not supported; treat as 8G
value = kFilterCtl_Range8G;
m_gsPerLSB = 0.004;
break;
default:
throw new IllegalArgumentException(range + " unsupported");
-
}
// Specify the data format to read
- byte[] commands = new byte[]{kRegWrite, kFilterCtlRegister, (byte) (kFilterCtl_ODR_100Hz
- | value)};
+ byte[] commands =
+ new byte[] {kRegWrite, kFilterCtlRegister, (byte) (kFilterCtl_ODR_100Hz | value)};
m_spi.write(commands, commands.length);
if (m_simRange != null) {
@@ -182,7 +189,6 @@
}
}
-
@Override
public double getX() {
return getAcceleration(Axes.kX);
@@ -257,16 +263,17 @@
}
@Override
- public void initSendable(SendableBuilder builder) {
+ public void initSendable(NTSendableBuilder builder) {
builder.setSmartDashboardType("3AxisAccelerometer");
NetworkTableEntry entryX = builder.getEntry("X");
NetworkTableEntry entryY = builder.getEntry("Y");
NetworkTableEntry entryZ = builder.getEntry("Z");
- builder.setUpdateTable(() -> {
- AllAxes data = getAccelerations();
- entryX.setDouble(data.XAxis);
- entryY.setDouble(data.YAxis);
- entryZ.setDouble(data.ZAxis);
- });
+ builder.setUpdateTable(
+ () -> {
+ AllAxes data = getAccelerations();
+ entryX.setDouble(data.XAxis);
+ entryY.setDouble(data.YAxis);
+ entryZ.setDouble(data.ZAxis);
+ });
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java
index 78ab8c4..5a826de 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java
@@ -1,22 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimBoolean;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
+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.interfaces.Gyro;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
/**
* Use a rate gyro to return the robots heading relative to a starting position. The Gyro class
@@ -29,7 +27,7 @@
* an ADXRS Gyro is supported.
*/
@SuppressWarnings({"TypeName", "AbbreviationAsWordInName", "PMD.UnusedPrivateField"})
-public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable, AutoCloseable {
+public class ADXRS450_Gyro implements Gyro, Sendable {
private static final double kSamplePeriod = 0.0005;
private static final double kCalibrationSampleTime = 5.0;
private static final double kDegreePerSecondPerLSB = 0.0125;
@@ -45,16 +43,13 @@
private static final int kSNLowRegister = 0x10;
private SPI m_spi;
- private SPI.Port m_port;
private SimDevice m_simDevice;
private SimBoolean m_simConnected;
private SimDouble m_simAngle;
private SimDouble m_simRate;
- /**
- * Constructor. Uses the onboard CS0.
- */
+ /** Constructor. Uses the onboard CS0. */
public ADXRS450_Gyro() {
this(SPI.Port.kOnboardCS0);
}
@@ -66,14 +61,13 @@
*/
public ADXRS450_Gyro(SPI.Port port) {
m_spi = new SPI(port);
- m_port = port;
// simulation
- m_simDevice = SimDevice.create("ADXRS450_Gyro", port.value);
+ m_simDevice = SimDevice.create("Gyro:ADXRS450", port.value);
if (m_simDevice != null) {
- m_simConnected = m_simDevice.createBoolean("Connected", false, true);
- m_simAngle = m_simDevice.createDouble("Angle", false, 0.0);
- m_simRate = m_simDevice.createDouble("Rate", false, 0.0);
+ m_simConnected = m_simDevice.createBoolean("connected", SimDevice.Direction.kInput, true);
+ m_simAngle = m_simDevice.createDouble("angle_x", SimDevice.Direction.kInput, 0.0);
+ m_simRate = m_simDevice.createDouble("rate_x", SimDevice.Direction.kInput, 0.0);
}
m_spi.setClockRate(3000000);
@@ -87,13 +81,12 @@
if ((readRegister(kPIDRegister) & 0xff00) != 0x5200) {
m_spi.close();
m_spi = null;
- DriverStation.reportError("could not find ADXRS450 gyro on SPI port " + port.value,
- false);
+ DriverStation.reportError("could not find ADXRS450 gyro on SPI port " + port.value, false);
return;
}
- m_spi.initAccumulator(kSamplePeriod, 0x20000000, 4, 0x0c00000e, 0x04000000, 10, 16,
- true, true);
+ m_spi.initAccumulator(
+ kSamplePeriod, 0x20000000, 4, 0x0c00000e, 0x04000000, 10, 16, true, true);
calibrate();
}
@@ -137,7 +130,7 @@
* @return The SPI port number.
*/
public int getPort() {
- return m_port.value;
+ return m_spi.getPort();
}
private boolean calcParity(int value) {
@@ -164,7 +157,7 @@
m_spi.read(false, buf, 4);
if ((buf.get(0) & 0xe0) == 0) {
- return 0; // error, return 0
+ return 0; // error, return 0
}
return (buf.getInt(0) >> 5) & 0xffff;
}
@@ -172,19 +165,14 @@
@Override
public void reset() {
if (m_simAngle != null) {
- m_simAngle.set(0.0);
- }
- if (m_simRate != null) {
- m_simRate.set(0.0);
+ m_simAngle.reset();
}
if (m_spi != null) {
m_spi.resetAccumulator();
}
}
- /**
- * Delete (free) the spi port used for the gyro and stop accumulating.
- */
+ /** Delete (free) the spi port used for the gyro and stop accumulating. */
@Override
public void close() {
SendableRegistry.remove(this);
@@ -219,4 +207,10 @@
}
return m_spi.getAccumulatorLastValue() * kDegreePerSecondPerLSB;
}
+
+ @Override
+ public void initSendable(SendableBuilder builder) {
+ builder.setSmartDashboardType("Gyro");
+ builder.addDoubleProperty("Value", this::getAngle, null);
+ }
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java
index 5a333db..f4b367a 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLED.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -58,8 +55,8 @@
/**
* Sets the led output data.
*
- * <p>If the output is enabled, this will start writing the next data cycle.
- * It is safe to call, even while output is enabled.
+ * <p>If the output is enabled, this will start writing the next data cycle. It is safe to call,
+ * even while output is enabled.
*
* @param buffer the buffer to write
*/
@@ -77,10 +74,16 @@
* @param lowTime1NanoSeconds low time for 1 bit
* @param highTime1NanoSeconds high time for 1 bit
*/
- public void setBitTiming(int lowTime0NanoSeconds, int highTime0NanoSeconds,
- int lowTime1NanoSeconds, int highTime1NanoSeconds) {
- AddressableLEDJNI.setBitTiming(m_handle, lowTime0NanoSeconds,
- highTime0NanoSeconds, lowTime1NanoSeconds,
+ public void setBitTiming(
+ int lowTime0NanoSeconds,
+ int highTime0NanoSeconds,
+ int lowTime1NanoSeconds,
+ int highTime1NanoSeconds) {
+ AddressableLEDJNI.setBitTiming(
+ m_handle,
+ lowTime0NanoSeconds,
+ highTime0NanoSeconds,
+ lowTime1NanoSeconds,
highTime1NanoSeconds);
}
@@ -104,9 +107,7 @@
AddressableLEDJNI.start(m_handle);
}
- /**
- * Stops the output.
- */
+ /** Stops the output. */
public void stop() {
AddressableLEDJNI.stop(m_handle);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLEDBuffer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLEDBuffer.java
index 8b76429..c9659a1 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLEDBuffer.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AddressableLEDBuffer.java
@@ -1,18 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.util.Color;
import edu.wpi.first.wpilibj.util.Color8Bit;
-/**
- * Buffer storage for Addressable LEDs.
- */
+/** Buffer storage for Addressable LEDs. */
public class AddressableLEDBuffer {
byte[] m_buffer;
@@ -29,9 +24,9 @@
* Sets a specific led in the buffer.
*
* @param index the index to write
- * @param r the r value [0-255]
- * @param g the g value [0-255]
- * @param b the b value [0-255]
+ * @param r the r value [0-255]
+ * @param g the g value [0-255]
+ * @param b the b value [0-255]
*/
@SuppressWarnings("ParameterName")
public void setRGB(int index, int r, int g, int b) {
@@ -45,9 +40,9 @@
* Sets a specific led in the buffer.
*
* @param index the index to write
- * @param h the h value [0-180]
- * @param s the s value [0-255]
- * @param v the v value [0-255]
+ * @param h the h value [0-180]
+ * @param s the s value [0-255]
+ * @param v the v value [0-255]
*/
@SuppressWarnings("ParameterName")
public void setHSV(final int index, final int h, final int s, final int v) {
@@ -92,10 +87,7 @@
* @param color The color of the LED
*/
public void setLED(int index, Color color) {
- setRGB(index,
- (int) (color.red * 255),
- (int) (color.green * 255),
- (int) (color.blue * 255));
+ setRGB(index, (int) (color.red * 255), (int) (color.green * 255), (int) (color.blue * 255));
}
/**
@@ -124,8 +116,8 @@
* @return the LED color at the specified index
*/
public Color8Bit getLED8Bit(int index) {
- return new Color8Bit(m_buffer[index * 4 + 2] & 0xFF, m_buffer[index * 4 + 1] & 0xFF,
- m_buffer[index * 4] & 0xFF);
+ return new Color8Bit(
+ m_buffer[index * 4 + 2] & 0xFF, m_buffer[index * 4 + 1] & 0xFF, m_buffer[index * 4] & 0xFF);
}
/**
@@ -135,9 +127,9 @@
* @return the LED color at the specified index
*/
public Color getLED(int index) {
- return new Color((m_buffer[index * 4 + 2] & 0xFF) / 255.0,
- (m_buffer[index * 4 + 1] & 0xFF) / 255.0,
- (m_buffer[index * 4] & 0xFF) / 255.0);
+ return new Color(
+ (m_buffer[index * 4 + 2] & 0xFF) / 255.0,
+ (m_buffer[index * 4 + 1] & 0xFF) / 255.0,
+ (m_buffer[index * 4] & 0xFF) / 255.0);
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogAccelerometer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogAccelerometer.java
index 41c5b38..a2405b8 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogAccelerometer.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogAccelerometer.java
@@ -1,37 +1,31 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Handle operation of an analog accelerometer. The accelerometer reads acceleration directly
* through the sensor. Many sensors have multiple axis and can be treated as multiple devices. Each
* is calibrated by finding the center value over a period of time.
*/
-public class AnalogAccelerometer implements PIDSource, Sendable, AutoCloseable {
+public class AnalogAccelerometer implements Sendable, AutoCloseable {
private AnalogInput m_analogChannel;
private double m_voltsPerG = 1.0;
private double m_zeroGVoltage = 2.5;
private final boolean m_allocatedChannel;
- protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
- /**
- * Common initialization.
- */
+ /** Common initialization. */
private void initAccelerometer() {
- HAL.report(tResourceType.kResourceType_Accelerometer,
- m_analogChannel.getChannel() + 1);
+ HAL.report(tResourceType.kResourceType_Accelerometer, m_analogChannel.getChannel() + 1);
SendableRegistry.addLW(this, "Accelerometer", m_analogChannel.getChannel());
}
@@ -53,7 +47,7 @@
* read as an analog channel as well as through the Accelerometer class.
*
* @param channel The existing AnalogInput object for the analog input the accelerometer is
- * connected to
+ * connected to
*/
public AnalogAccelerometer(final AnalogInput channel) {
this(channel, false);
@@ -66,9 +60,7 @@
initAccelerometer();
}
- /**
- * Delete the analog components used for the accelerometer.
- */
+ /** Delete the analog components used for the accelerometer. */
@Override
public void close() {
SendableRegistry.remove(this);
@@ -117,26 +109,6 @@
}
@Override
- public void setPIDSourceType(PIDSourceType pidSource) {
- m_pidSource = pidSource;
- }
-
- @Override
- public PIDSourceType getPIDSourceType() {
- return m_pidSource;
- }
-
- /**
- * Get the Acceleration for the PID Source parent.
- *
- * @return The current acceleration in Gs.
- */
- @Override
- public double pidGet() {
- return getAcceleration();
- }
-
- @Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Accelerometer");
builder.addDoubleProperty("Value", this::getAcceleration, null);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogEncoder.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogEncoder.java
index bea4e6a..24989dd 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogEncoder.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogEncoder.java
@@ -1,21 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.SimDevice;
+import edu.wpi.first.hal.SimDevice.Direction;
import edu.wpi.first.hal.SimDouble;
+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.AnalogTriggerOutput.AnalogTriggerType;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-/**
- * Class for supporting continuous analog encoders, such as the US Digital MA3.
- */
+/** Class for supporting continuous analog encoders, such as the US Digital MA3. */
public class AnalogEncoder implements Sendable, AutoCloseable {
private final AnalogInput m_analogInput;
private AnalogTrigger m_analogTrigger;
@@ -28,6 +25,15 @@
protected SimDouble m_simPosition;
/**
+ * Construct a new AnalogEncoder attached to a specific AnalogIn channel.
+ *
+ * @param channel the analog input channel to attach to
+ */
+ public AnalogEncoder(int channel) {
+ this(new AnalogInput(channel));
+ }
+
+ /**
* Construct a new AnalogEncoder attached to a specific AnalogInput.
*
* @param analogInput the analog input to attach to
@@ -44,7 +50,7 @@
m_simDevice = SimDevice.create("AnalogEncoder", m_analogInput.getChannel());
if (m_simDevice != null) {
- m_simPosition = m_simDevice.createDouble("Position", false, 0.0);
+ m_simPosition = m_simDevice.createDouble("Position", Direction.kInput, 0.0);
}
// Limits need to be 25% from each end
@@ -89,9 +95,9 @@
/**
* Get the offset of position relative to the last reset.
*
- * <p>getPositionInRotation() - getPositionOffset() will give an encoder absolute
- * position relative to the last reset. This could potentially be negative,
- * which needs to be accounted for.
+ * <p>getPositionInRotation() - getPositionOffset() will give an encoder absolute position
+ * relative to the last reset. This could potentially be negative, which needs to be accounted
+ * for.
*
* @return the position offset
*/
@@ -100,11 +106,10 @@
}
/**
- * Set the distance per rotation of the encoder. This sets the multiplier used
- * to determine the distance driven based on the rotation value from the
- * encoder. Set this value based on the how far the mechanism travels in 1
- * rotation of the encoder, and factor in gearing reductions following the
- * encoder shaft. This distance can be in any units you like, linear or angular.
+ * Set the distance per rotation of the encoder. This sets the multiplier used to determine the
+ * distance driven based on the rotation value from the encoder. Set this value based on the how
+ * far the mechanism travels in 1 rotation of the encoder, and factor in gearing reductions
+ * following the encoder shaft. This distance can be in any units you like, linear or angular.
*
* @param distancePerRotation the distance per rotation of the encoder
*/
@@ -115,16 +120,15 @@
/**
* Get the distance per rotation for this encoder.
*
- * @return The scale factor that will be used to convert rotation to useful
- * units.
+ * @return The scale factor that will be used to convert rotation to useful units.
*/
public double getDistancePerRotation() {
return m_distancePerRotation;
}
/**
- * Get the distance the sensor has driven since the last reset as scaled by the
- * value from {@link #setDistancePerRotation(double)}.
+ * Get the distance the sensor has driven since the last reset as scaled by the value from {@link
+ * #setDistancePerRotation(double)}.
*
* @return The distance driven since the last reset
*/
@@ -141,9 +145,7 @@
return m_analogInput.getChannel();
}
- /**
- * Reset the Encoder distance to zero.
- */
+ /** Reset the Encoder distance to zero. */
public void reset() {
m_counter.reset();
m_positionOffset = m_analogInput.getVoltage();
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogGyro.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogGyro.java
index 0ed22d9..c9b9126 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogGyro.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogGyro.java
@@ -1,19 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+
import edu.wpi.first.hal.AnalogGyroJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
+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.interfaces.Gyro;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
/**
* Use a rate gyro to return the robots heading relative to a starting position. The Gyro class
@@ -24,16 +23,14 @@
*
* <p>This class is for gyro sensors that connect to an analog input.
*/
-public class AnalogGyro extends GyroBase implements Gyro, PIDSource, Sendable, AutoCloseable {
+public class AnalogGyro implements Gyro, Sendable {
private static final double kDefaultVoltsPerDegreePerSecond = 0.007;
protected AnalogInput m_analog;
private boolean m_channelAllocated;
private int m_gyroHandle;
- /**
- * Initialize the gyro. Calibration is handled by calibrate().
- */
+ /** Initialize the gyro. Calibration is handled by calibrate(). */
public void initGyro() {
if (m_gyroHandle == 0) {
m_gyroHandle = AnalogGyroJNI.initializeAnalogGyro(m_analog.m_port);
@@ -54,7 +51,7 @@
* Gyro constructor using the channel number.
*
* @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
- * channels 0-1.
+ * channels 0-1.
*/
public AnalogGyro(int channel) {
this(new AnalogInput(channel));
@@ -67,7 +64,7 @@
* channel needs to be shared.
*
* @param channel The AnalogInput object that the gyro is connected to. Gyros can only be used on
- * on-board channels 0-1.
+ * on-board channels 0-1.
*/
public AnalogGyro(AnalogInput channel) {
requireNonNullParam(channel, "channel", "AnalogGyro");
@@ -82,9 +79,9 @@
* offset values. Bypasses calibration.
*
* @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
- * channels 0-1.
- * @param center Preset uncalibrated value to use as the accumulator center value.
- * @param offset Preset uncalibrated value to use as the gyro offset.
+ * channels 0-1.
+ * @param center Preset uncalibrated value to use as the accumulator center value.
+ * @param offset Preset uncalibrated value to use as the gyro offset.
*/
public AnalogGyro(int channel, int center, double offset) {
this(new AnalogInput(channel), center, offset);
@@ -97,17 +94,18 @@
* the center and offset values. Bypasses calibration.
*
* @param channel The analog channel the gyro is connected to. Gyros can only be used on on-board
- * channels 0-1.
- * @param center Preset uncalibrated value to use as the accumulator center value.
- * @param offset Preset uncalibrated value to use as the gyro offset.
+ * channels 0-1.
+ * @param center Preset uncalibrated value to use as the accumulator center value.
+ * @param offset Preset uncalibrated value to use as the gyro offset.
*/
public AnalogGyro(AnalogInput channel, int center, double offset) {
requireNonNullParam(channel, "channel", "AnalogGyro");
m_analog = channel;
initGyro();
- AnalogGyroJNI.setAnalogGyroParameters(m_gyroHandle, kDefaultVoltsPerDegreePerSecond,
- offset, center);
+ AnalogGyroJNI.setAnalogGyroParameters(
+ m_gyroHandle, kDefaultVoltsPerDegreePerSecond,
+ offset, center);
reset();
}
@@ -116,9 +114,7 @@
AnalogGyroJNI.resetAnalogGyro(m_gyroHandle);
}
- /**
- * Delete (free) the accumulator and the analog components used for the gyro.
- */
+ /** Delete (free) the accumulator and the analog components used for the gyro. */
@Override
public void close() {
SendableRegistry.remove(this);
@@ -173,8 +169,7 @@
* @param voltsPerDegreePerSecond The sensitivity in Volts/degree/second.
*/
public void setSensitivity(double voltsPerDegreePerSecond) {
- AnalogGyroJNI.setAnalogGyroVoltsPerDegreePerSecond(m_gyroHandle,
- voltsPerDegreePerSecond);
+ AnalogGyroJNI.setAnalogGyroVoltsPerDegreePerSecond(m_gyroHandle, voltsPerDegreePerSecond);
}
/**
@@ -196,4 +191,10 @@
public AnalogInput getAnalogInput() {
return m_analog;
}
+
+ @Override
+ public void initSendable(SendableBuilder builder) {
+ builder.setSmartDashboardType("Gyro");
+ builder.addDoubleProperty("Value", this::getAngle, null);
+ }
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogInput.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogInput.java
index 3298058..e3bedcb 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogInput.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogInput.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -13,8 +10,9 @@
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.util.AllocationException;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Analog channel class.
@@ -28,13 +26,12 @@
* accumulated effectively increasing the resolution, while the averaged samples are divided by the
* number of samples to retain the resolution, but get more stable values.
*/
-public class AnalogInput implements PIDSource, Sendable, AutoCloseable {
+public class AnalogInput implements Sendable, AutoCloseable {
private static final int kAccumulatorSlot = 1;
int m_port; // explicit no modifier, private and package accessible.
private int m_channel;
private static final int[] kAccumulatorChannels = {0, 1};
private long m_accumulatorOffset;
- protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
/**
* Construct an analog channel.
@@ -183,13 +180,16 @@
return AnalogJNI.getAnalogOversampleBits(m_port);
}
- /**
- * Initialize the accumulator.
- */
+ /** Initialize the accumulator. */
public void initAccumulator() {
if (!isAccumulatorChannel()) {
- throw new AllocationException("Accumulators are only available on slot " + kAccumulatorSlot
- + " on channels " + kAccumulatorChannels[0] + ", " + kAccumulatorChannels[1]);
+ throw new AllocationException(
+ "Accumulators are only available on slot "
+ + kAccumulatorSlot
+ + " on channels "
+ + kAccumulatorChannels[0]
+ + ", "
+ + kAccumulatorChannels[1]);
}
m_accumulatorOffset = 0;
AnalogJNI.initAccumulator(m_port);
@@ -206,9 +206,7 @@
m_accumulatorOffset = initialValue;
}
- /**
- * Resets the accumulator to the initial value.
- */
+ /** Resets the accumulator to the initial value. */
public void resetAccumulator() {
AnalogJNI.resetAccumulator(m_port);
@@ -218,7 +216,6 @@
final double overSamples = 1 << getOversampleBits();
final double averageSamples = 1 << getAverageBits();
Timer.delay(sampleTime * overSamples * averageSamples);
-
}
/**
@@ -231,6 +228,8 @@
* <p>This center value is based on the output of the oversampled and averaged source the
* accumulator channel. Because of this, any non-zero oversample bits will affect the size of the
* value for this field.
+ *
+ * @param center The accumulator's center value.
*/
public void setAccumulatorCenter(int center) {
AnalogJNI.setAccumulatorCenter(m_port, center);
@@ -325,26 +324,6 @@
return AnalogJNI.getAnalogSampleRate();
}
- @Override
- public void setPIDSourceType(PIDSourceType pidSource) {
- m_pidSource = pidSource;
- }
-
- @Override
- public PIDSourceType getPIDSourceType() {
- return m_pidSource;
- }
-
- /**
- * Get the average voltage for use with PIDController.
- *
- * @return the average voltage
- */
- @Override
- public double pidGet() {
- return getAverageVoltage();
- }
-
/**
* Indicates this input is used by a simulated device.
*
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogOutput.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogOutput.java
index feb6e1e..299d89c 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogOutput.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogOutput.java
@@ -1,21 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2014-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.AnalogJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
-/**
- * Analog output class.
- */
+/** Analog output class. */
public class AnalogOutput implements Sendable, AutoCloseable {
private int m_port;
private int m_channel;
@@ -46,6 +42,8 @@
/**
* Get the channel of this AnalogOutput.
+ *
+ * @return The channel of this AnalogOutput.
*/
public int getChannel() {
return m_channel;
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogPotentiometer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogPotentiometer.java
index 9d5d49d..4a5bd75 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogPotentiometer.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogPotentiometer.java
@@ -1,27 +1,23 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import edu.wpi.first.wpilibj.interfaces.Potentiometer;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Class for reading analog potentiometers. Analog potentiometers read in an analog voltage that
* corresponds to a position. The position is in whichever units you choose, by way of the scaling
* and offset constants passed to the constructor.
*/
-public class AnalogPotentiometer implements Potentiometer, Sendable, AutoCloseable {
+public class AnalogPotentiometer implements Sendable, AutoCloseable {
private AnalogInput m_analogInput;
private boolean m_initAnalogInput;
private double m_fullRange;
private double m_offset;
- protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
/**
* AnalogPotentiometer constructor.
@@ -29,13 +25,13 @@
* <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
* have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
* 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
- * point after scaling is 135 degrees. This will calculate the result from the fullRange times
- * the fraction of the supply voltage, plus the offset.
+ * point after scaling is 135 degrees. This will calculate the result from the fullRange times the
+ * fraction of the supply voltage, plus the offset.
*
- * @param channel The analog input channel this potentiometer is plugged into. 0-3 are
- * on-board and 4-7 are on the MXP port.
+ * @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board
+ * and 4-7 are on the MXP port.
* @param fullRange The scaling to multiply the fraction by to get a meaningful unit.
- * @param offset The offset to add to the scaled value for controlling the zero value
+ * @param offset The offset to add to the scaled value for controlling the zero value
*/
public AnalogPotentiometer(final int channel, double fullRange, double offset) {
this(new AnalogInput(channel), fullRange, offset);
@@ -47,16 +43,15 @@
* AnalogPotentiometer constructor.
*
* <p>Use the fullRange and offset values so that the output produces meaningful values. I.E: you
- * have a 270 degree potentiometer and you want the output to be degrees with the halfway point
- * as 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
- * point after scaling is 135 degrees. This will calculate the result from the fullRange times
- * the fraction of the supply voltage, plus the offset.
+ * have a 270 degree potentiometer and you want the output to be degrees with the halfway point as
+ * 0 degrees. The fullRange value is 270.0(degrees) and the offset is -135.0 since the halfway
+ * point after scaling is 135 degrees. This will calculate the result from the fullRange times the
+ * fraction of the supply voltage, plus the offset.
*
- * @param input The {@link AnalogInput} this potentiometer is plugged into.
- * @param fullRange The angular value (in desired units) representing the full
- * 0-5V range of the input.
- * @param offset The angular value (in desired units) representing the
- * angular output at 0V.
+ * @param input The {@link AnalogInput} this potentiometer is plugged into.
+ * @param fullRange The angular value (in desired units) representing the full 0-5V range of the
+ * input.
+ * @param offset The angular value (in desired units) representing the angular output at 0V.
*/
public AnalogPotentiometer(final AnalogInput input, double fullRange, double offset) {
SendableRegistry.addLW(this, "AnalogPotentiometer", input.getChannel());
@@ -70,13 +65,13 @@
/**
* AnalogPotentiometer constructor.
*
- * <p>Use the scale value so that the output produces meaningful values. I.E: you
- * have a 270 degree potentiometer and you want the output to be degrees with the starting point
- * as 0 degrees. The scale value is 270.0(degrees).
+ * <p>Use the scale value so that the output produces meaningful values. I.E: you have a 270
+ * degree potentiometer and you want the output to be degrees with the starting point as 0
+ * degrees. The scale value is 270.0(degrees).
*
- * @param channel The analog input channel this potentiometer is plugged into. 0-3 are
- * on-board and 4-7 are on the MXP port.
- * @param scale The scaling to multiply the voltage by to get a meaningful unit.
+ * @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board
+ * and 4-7 are on the MXP port.
+ * @param scale The scaling to multiply the voltage by to get a meaningful unit.
*/
public AnalogPotentiometer(final int channel, double scale) {
this(channel, scale, 0);
@@ -101,8 +96,8 @@
*
* <p>The potentiometer will return a value between 0 and 1.0.
*
- * @param channel The analog input channel this potentiometer is plugged into. 0-3 are
- * on-board and 4-7 are on the MXP port.
+ * @param channel The analog input channel this potentiometer is plugged into. 0-3 are on-board
+ * and 4-7 are on the MXP port.
*/
public AnalogPotentiometer(final int channel) {
this(channel, 1, 0);
@@ -124,36 +119,12 @@
*
* @return The current position of the potentiometer.
*/
- @Override
public double get() {
if (m_analogInput == null) {
return m_offset;
}
- return (m_analogInput.getAverageVoltage() / RobotController.getVoltage5V())
- * m_fullRange + m_offset;
- }
-
- @Override
- public void setPIDSourceType(PIDSourceType pidSource) {
- if (!pidSource.equals(PIDSourceType.kDisplacement)) {
- throw new IllegalArgumentException("Only displacement PID is allowed for potentiometers.");
- }
- m_pidSource = pidSource;
- }
-
- @Override
- public PIDSourceType getPIDSourceType() {
- return m_pidSource;
- }
-
- /**
- * Implement the PIDSource interface.
- *
- * @return The current reading.
- */
- @Override
- public double pidGet() {
- return get();
+ return (m_analogInput.getAverageVoltage() / RobotController.getVoltage5V()) * m_fullRange
+ + m_offset;
}
@Override
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTrigger.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTrigger.java
index 282a346..d5825c1 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTrigger.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTrigger.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -11,18 +8,14 @@
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.util.BoundaryException;
+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.AnalogTriggerOutput.AnalogTriggerType;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Class for creating and configuring Analog Triggers.
- */
+/** Class for creating and configuring Analog Triggers. */
public class AnalogTrigger implements Sendable, AutoCloseable {
- /**
- * Exceptions dealing with improper operation of the Analog trigger.
- */
+ /** Exceptions dealing with improper operation of the Analog trigger. */
@SuppressWarnings("serial")
public static class AnalogTriggerException extends RuntimeException {
/**
@@ -33,13 +26,11 @@
public AnalogTriggerException(String message) {
super(message);
}
-
}
- /**
- * Where the analog trigger is attached.
- */
+ /** Where the analog trigger is attached. */
protected int m_port;
+
protected AnalogInput m_analogInput;
protected DutyCycle m_dutyCycle;
protected boolean m_ownsAnalog;
@@ -162,8 +153,7 @@
}
/**
- * Return the index of the analog trigger. This is the FPGA index of this analog trigger
- * instance.
+ * Return the index of the analog trigger. This is the FPGA index of this analog trigger instance.
*
* @return The index of the analog trigger.
*/
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTriggerOutput.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTriggerOutput.java
index f9fe950..0f513b4 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTriggerOutput.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AnalogTriggerOutput.java
@@ -1,18 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+
import edu.wpi.first.hal.AnalogJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
/**
* Class to represent a specific output from an analog trigger. This class is used to get the
@@ -41,9 +39,7 @@
* limited.
*/
public class AnalogTriggerOutput extends DigitalSource implements Sendable {
- /**
- * Exceptions dealing with improper operation of the Analog trigger output.
- */
+ /** Exceptions dealing with improper operation of the Analog trigger output. */
@SuppressWarnings("serial")
public static class AnalogTriggerOutputException extends RuntimeException {
/**
@@ -65,7 +61,7 @@
* <p>Because this class derives from DigitalSource, it can be passed into routing functions for
* Counter, Encoder, etc.
*
- * @param trigger The trigger for which this is an output.
+ * @param trigger The trigger for which this is an output.
* @param outputType An enum that specifies the output on the trigger to represent.
*/
public AnalogTriggerOutput(AnalogTrigger trigger, final AnalogTriggerType outputType) {
@@ -74,8 +70,10 @@
m_trigger = trigger;
m_outputType = outputType;
- HAL.report(tResourceType.kResourceType_AnalogTriggerOutput,
- trigger.getIndex() + 1, outputType.value + 1);
+ HAL.report(
+ tResourceType.kResourceType_AnalogTriggerOutput,
+ trigger.getIndex() + 1,
+ outputType.value + 1);
}
/**
@@ -107,15 +105,13 @@
return true;
}
- /**
- * Defines the state in which the AnalogTrigger triggers.
- */
+ /** Defines the state in which the AnalogTrigger triggers. */
public enum AnalogTriggerType {
- kInWindow(AnalogJNI.AnalogTriggerType.kInWindow), kState(AnalogJNI.AnalogTriggerType.kState),
+ kInWindow(AnalogJNI.AnalogTriggerType.kInWindow),
+ kState(AnalogJNI.AnalogTriggerType.kState),
kRisingPulse(AnalogJNI.AnalogTriggerType.kRisingPulse),
kFallingPulse(AnalogJNI.AnalogTriggerType.kFallingPulse);
- @SuppressWarnings("MemberName")
private final int value;
AnalogTriggerType(int value) {
@@ -124,6 +120,5 @@
}
@Override
- public void initSendable(SendableBuilder builder) {
- }
+ public void initSendable(SendableBuilder builder) {}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java
new file mode 100644
index 0000000..1981671
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java
@@ -0,0 +1,140 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BiConsumer;
+
+/**
+ * Class for handling asynchronous interrupts using a callback thread.
+ *
+ * <p>By default, interrupts will occur on rising edge. Callbacks are disabled by default, and
+ * enable() must be called before they will occur.
+ *
+ * <p>Both rising and falling edges can be indicated in one callback if both a rising and falling
+ * edge occurred since the previous callback.
+ *
+ * <p>Synchronous (blocking) interrupts are handled by the SynchronousInterrupt class.
+ */
+public class AsynchronousInterrupt implements AutoCloseable {
+ private final BiConsumer<Boolean, Boolean> m_callback;
+ private final SynchronousInterrupt m_interrupt;
+
+ private final AtomicBoolean m_keepRunning = new AtomicBoolean(false);
+ private Thread m_thread;
+
+ /**
+ * Construct a new asynchronous interrupt using a Digital Source.
+ *
+ * <p>At construction, the interrupt will trigger on the rising edge.
+ *
+ * <p>Callbacks will not be triggered until enable() is called.
+ *
+ * <p>The first bool in the callback indicates the rising edge triggered the interrupt, the second
+ * bool is falling edge.
+ *
+ * @param source The digital source to use.
+ * @param callback The callback to call on an interrupt
+ */
+ public AsynchronousInterrupt(DigitalSource source, BiConsumer<Boolean, Boolean> callback) {
+ m_callback = requireNonNullParam(callback, "callback", "AsynchronousInterrupt");
+ m_interrupt = new SynchronousInterrupt(source);
+ }
+
+ /**
+ * Closes the interrupt.
+ *
+ * <p>This does not close the associated digital source.
+ *
+ * <p>This will disable the interrupt if it is enabled.
+ */
+ @Override
+ public void close() {
+ disable();
+ m_interrupt.close();
+ }
+
+ /**
+ * Enables interrupt callbacks. Before this, callbacks will not occur. Does nothing if already
+ * enabled.
+ */
+ public void enable() {
+ if (m_keepRunning.get()) {
+ return;
+ }
+
+ m_keepRunning.set(true);
+ m_thread = new Thread(this::threadMain);
+ m_thread.start();
+ }
+
+ /** Disables interrupt callbacks. Does nothing if already disabled. */
+ public void disable() {
+ m_keepRunning.set(false);
+ m_interrupt.wakeupWaitingInterrupt();
+ if (m_thread != null) {
+ if (m_thread.isAlive()) {
+ try {
+ m_thread.interrupt();
+ m_thread.join();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ m_thread = null;
+ }
+ }
+
+ /**
+ * Set which edges to trigger the interrupt on.
+ *
+ * @param risingEdge Trigger on rising edge
+ * @param fallingEdge Trigger on falling edge
+ */
+ public void setInterruptEdges(boolean risingEdge, boolean fallingEdge) {
+ m_interrupt.setInterruptEdges(risingEdge, fallingEdge);
+ }
+
+ /**
+ * Get the timestamp of the last rising edge.
+ *
+ * <p>This function does not require the interrupt to be enabled to work.
+ *
+ * <p>This only works if rising edge was configured using setInterruptEdges.
+ *
+ * @return the timestamp in seconds relative to getFPGATime
+ */
+ public double getRisingTimestamp() {
+ return m_interrupt.getRisingTimestamp();
+ }
+
+ /**
+ * Get the timestamp of the last falling edge.
+ *
+ * <p>This function does not require the interrupt to be enabled to work.
+ *
+ * <p>This only works if falling edge was configured using setInterruptEdges.
+ *
+ * @return the timestamp in seconds relative to getFPGATime
+ */
+ public double getFallingTimestamp() {
+ return m_interrupt.getFallingTimestamp();
+ }
+
+ private void threadMain() {
+ while (m_keepRunning.get()) {
+ var result = m_interrupt.waitForInterruptRaw(10, false);
+ if (!m_keepRunning.get()) {
+ break;
+ }
+ if (result == 0) {
+ continue;
+ }
+ m_callback.accept((result & 0x1) != 0, (result & 0x100) != 0);
+ }
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/BuiltInAccelerometer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/BuiltInAccelerometer.java
index e367756..76c282a 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/BuiltInAccelerometer.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/BuiltInAccelerometer.java
@@ -1,18 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2014-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.AccelerometerJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
+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.interfaces.Accelerometer;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
/**
* Built-in accelerometer.
@@ -31,9 +29,7 @@
SendableRegistry.addLW(this, "BuiltInAccel", 0);
}
- /**
- * Constructor. The accelerometer will measure +/-8 g-forces
- */
+ /** Constructor. The accelerometer will measure +/-8 g-forces */
public BuiltInAccelerometer() {
this(Range.k8G);
}
@@ -60,7 +56,6 @@
case k16G:
default:
throw new IllegalArgumentException(range + " range not supported (use k2G, k4G, or k8G)");
-
}
AccelerometerJNI.setAccelerometerActive(true);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/CAN.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/CAN.java
index 2dde3ab..3dc6c1d 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/CAN.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/CAN.java
@@ -1,29 +1,24 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.io.Closeable;
-
import edu.wpi.first.hal.CANAPIJNI;
import edu.wpi.first.hal.CANData;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
+import java.io.Closeable;
/**
- * High level class for interfacing with CAN devices conforming to
- * the standard CAN spec.
+ * High level class for interfacing with CAN devices conforming to the standard CAN spec.
*
- * <p>No packets that can be sent gets blocked by the RoboRIO, so all methods
- * work identically in all robot modes.
+ * <p>No packets that can be sent gets blocked by the RoboRIO, so all methods work identically in
+ * all robot modes.
*
- * <p>All methods are thread safe, however the CANData object passed into the
- * read methods and the byte[] passed into the write methods need to not
- * be modified for the duration of their respective calls.
+ * <p>All methods are thread safe, however the CANData object passed into the read methods and the
+ * byte[] passed into the write methods need to not be modified for the duration of their respective
+ * calls.
*/
public class CAN implements Closeable {
public static final int kTeamManufacturer = 8;
@@ -32,9 +27,8 @@
private final int m_handle;
/**
- * Create a new CAN communication interface with the specific device ID.
- * This uses the team manufacturer and device types.
- * The device ID is 6 bits (0-63).
+ * Create a new CAN communication interface with the specific device ID. This uses the team
+ * manufacturer and device types. The device ID is 6 bits (0-63).
*
* @param deviceId The device id
*/
@@ -44,22 +38,19 @@
}
/**
- * Create a new CAN communication interface with a specific device ID,
- * manufacturer and device type. The device ID is 6 bits, the
- * manufacturer is 8 bits, and the device type is 5 bits.
+ * Create a new CAN communication interface with a specific device ID, manufacturer and device
+ * type. The device ID is 6 bits, the manufacturer is 8 bits, and the device type is 5 bits.
*
- * @param deviceId The device ID
+ * @param deviceId The device ID
* @param deviceManufacturer The device manufacturer
- * @param deviceType The device type
+ * @param deviceType The device type
*/
public CAN(int deviceId, int deviceManufacturer, int deviceType) {
m_handle = CANAPIJNI.initializeCAN(deviceManufacturer, deviceId, deviceType);
HAL.report(tResourceType.kResourceType_CAN, deviceId + 1);
}
- /**
- * Closes the CAN communication.
- */
+ /** Closes the CAN communication. */
@Override
public void close() {
if (m_handle != 0) {
@@ -78,8 +69,8 @@
}
/**
- * Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits.
- * The RoboRIO will automatically repeat the packet at the specified interval
+ * Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits. The RoboRIO
+ * will automatically repeat the packet at the specified interval
*
* @param data The data to write (8 bytes max)
* @param apiId The API ID to write.
@@ -90,8 +81,8 @@
}
/**
- * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits.
- * The length by spec must match what is returned by the responding device
+ * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. The length by spec
+ * must match what is returned by the responding device
*
* @param length The length to request (0 to 8)
* @param apiId The API ID to write.
@@ -105,29 +96,32 @@
*
* @param data The data to write (8 bytes max)
* @param apiId The API ID to write.
+ * @return TODO
*/
public int writePacketNoThrow(byte[] data, int apiId) {
return CANAPIJNI.writeCANPacketNoThrow(m_handle, data, apiId);
}
/**
- * Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits.
- * The RoboRIO will automatically repeat the packet at the specified interval
+ * Write a repeating packet to the CAN device with a specific ID. This ID is 10 bits. The RoboRIO
+ * will automatically repeat the packet at the specified interval
*
* @param data The data to write (8 bytes max)
* @param apiId The API ID to write.
* @param repeatMs The period to repeat the packet at.
+ * @return TODO
*/
public int writePacketRepeatingNoThrow(byte[] data, int apiId, int repeatMs) {
return CANAPIJNI.writeCANPacketRepeatingNoThrow(m_handle, data, apiId, repeatMs);
}
/**
- * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits.
- * The length by spec must match what is returned by the responding device
+ * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. The length by spec
+ * must match what is returned by the responding device
*
* @param length The length to request (0 to 8)
* @param apiId The API ID to write.
+ * @return TODO
*/
public int writeRTRFrameNoThrow(int length, int apiId) {
return CANAPIJNI.writeCANRTRFrameNoThrow(m_handle, length, apiId);
@@ -143,8 +137,8 @@
}
/**
- * Read a new CAN packet. This will only return properly once per packet
- * received. Multiple calls without receiving another packet will return false.
+ * Read a new CAN packet. This will only return properly once per packet received. Multiple calls
+ * without receiving another packet will return false.
*
* @param apiId The API ID to read.
* @param data Storage for the received data.
@@ -155,8 +149,8 @@
}
/**
- * Read a CAN packet. The will continuously return the last packet received,
- * without accounting for packet age.
+ * Read a CAN packet. The will continuously return the last packet received, without accounting
+ * for packet age.
*
* @param apiId The API ID to read.
* @param data Storage for the received data.
@@ -167,8 +161,8 @@
}
/**
- * Read a CAN packet. The will return the last packet received until the
- * packet is older then the requested timeout. Then it will return false.
+ * Read a CAN packet. The will return the last packet received until the packet is older then the
+ * requested timeout. Then it will return false.
*
* @param apiId The API ID to read.
* @param timeoutMs The timeout time for the packet
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/CameraServer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/CameraServer.java
deleted file mode 100644
index c8948b9..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/CameraServer.java
+++ /dev/null
@@ -1,783 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import edu.wpi.cscore.AxisCamera;
-import edu.wpi.cscore.CameraServerJNI;
-import edu.wpi.cscore.CvSink;
-import edu.wpi.cscore.CvSource;
-import edu.wpi.cscore.MjpegServer;
-import edu.wpi.cscore.UsbCamera;
-import edu.wpi.cscore.VideoEvent;
-import edu.wpi.cscore.VideoException;
-import edu.wpi.cscore.VideoListener;
-import edu.wpi.cscore.VideoMode;
-import edu.wpi.cscore.VideoMode.PixelFormat;
-import edu.wpi.cscore.VideoProperty;
-import edu.wpi.cscore.VideoSink;
-import edu.wpi.cscore.VideoSource;
-import edu.wpi.first.cameraserver.CameraServerSharedStore;
-import edu.wpi.first.networktables.EntryListenerFlags;
-import edu.wpi.first.networktables.NetworkTable;
-import edu.wpi.first.networktables.NetworkTableEntry;
-import edu.wpi.first.networktables.NetworkTableInstance;
-
-/**
- * Singleton class for creating and keeping camera servers.
- * Also publishes camera information to NetworkTables.
- *
- * @deprecated Replaced with edu.wpi.first.cameraserver.CameraServer
- */
-@Deprecated
-public final class CameraServer {
- public static final int kBasePort = 1181;
-
- @Deprecated
- public static final int kSize640x480 = 0;
- @Deprecated
- public static final int kSize320x240 = 1;
- @Deprecated
- public static final int kSize160x120 = 2;
-
- private static final String kPublishName = "/CameraPublisher";
- private static CameraServer server;
-
- /**
- * Get the CameraServer instance.
- */
- public static synchronized CameraServer getInstance() {
- if (server == null) {
- server = new CameraServer();
- }
- return server;
- }
-
- private final AtomicInteger m_defaultUsbDevice;
- private String m_primarySourceName;
- private final Map<String, VideoSource> m_sources;
- private final Map<String, VideoSink> m_sinks;
- private final Map<Integer, NetworkTable> m_tables; // indexed by source handle
- private final NetworkTable m_publishTable;
- private final VideoListener m_videoListener; //NOPMD
- private final int m_tableListener; //NOPMD
- private int m_nextPort;
- private String[] m_addresses;
-
- @SuppressWarnings("JavadocMethod")
- private static String makeSourceValue(int source) {
- switch (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))) {
- case kUsb:
- return "usb:" + CameraServerJNI.getUsbCameraPath(source);
- case kHttp: {
- String[] urls = CameraServerJNI.getHttpCameraUrls(source);
- if (urls.length > 0) {
- return "ip:" + urls[0];
- } else {
- return "ip:";
- }
- }
- case kCv:
- // FIXME: Should be "cv:", but LabVIEW dashboard requires "usb:".
- // https://github.com/wpilibsuite/allwpilib/issues/407
- return "usb:";
- default:
- return "unknown:";
- }
- }
-
- @SuppressWarnings("JavadocMethod")
- private static String makeStreamValue(String address, int port) {
- return "mjpg:http://" + address + ":" + port + "/?action=stream";
- }
-
- @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
- private synchronized String[] getSinkStreamValues(int sink) {
- // Ignore all but MjpegServer
- if (VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink)) != VideoSink.Kind.kMjpeg) {
- return new String[0];
- }
-
- // Get port
- int port = CameraServerJNI.getMjpegServerPort(sink);
-
- // Generate values
- ArrayList<String> values = new ArrayList<>(m_addresses.length + 1);
- String listenAddress = CameraServerJNI.getMjpegServerListenAddress(sink);
- if (!listenAddress.isEmpty()) {
- // If a listen address is specified, only use that
- values.add(makeStreamValue(listenAddress, port));
- } else {
- // Otherwise generate for hostname and all interface addresses
- values.add(makeStreamValue(CameraServerJNI.getHostname() + ".local", port));
- for (String addr : m_addresses) {
- if ("127.0.0.1".equals(addr)) {
- continue; // ignore localhost
- }
- values.add(makeStreamValue(addr, port));
- }
- }
-
- return values.toArray(new String[0]);
- }
-
- @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
- private synchronized String[] getSourceStreamValues(int source) {
- // Ignore all but HttpCamera
- if (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))
- != VideoSource.Kind.kHttp) {
- return new String[0];
- }
-
- // Generate values
- String[] values = CameraServerJNI.getHttpCameraUrls(source);
- for (int j = 0; j < values.length; j++) {
- values[j] = "mjpg:" + values[j];
- }
-
- if (CameraServerSharedStore.getCameraServerShared().isRoboRIO()) {
- // Look to see if we have a passthrough server for this source
- // Only do this on the roboRIO
- for (VideoSink i : m_sinks.values()) {
- int sink = i.getHandle();
- int sinkSource = CameraServerJNI.getSinkSource(sink);
- if (source == sinkSource
- && VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink))
- == VideoSink.Kind.kMjpeg) {
- // Add USB-only passthrough
- String[] finalValues = Arrays.copyOf(values, values.length + 1);
- int port = CameraServerJNI.getMjpegServerPort(sink);
- finalValues[values.length] = makeStreamValue("172.22.11.2", port);
- return finalValues;
- }
- }
- }
-
- return values;
- }
-
- @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
- private synchronized void updateStreamValues() {
- // Over all the sinks...
- for (VideoSink i : m_sinks.values()) {
- int sink = i.getHandle();
-
- // Get the source's subtable (if none exists, we're done)
- int source = CameraServerJNI.getSinkSource(sink);
- if (source == 0) {
- continue;
- }
- NetworkTable table = m_tables.get(source);
- if (table != null) {
- // Don't set stream values if this is a HttpCamera passthrough
- if (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))
- == VideoSource.Kind.kHttp) {
- continue;
- }
-
- // Set table value
- String[] values = getSinkStreamValues(sink);
- if (values.length > 0) {
- table.getEntry("streams").setStringArray(values);
- }
- }
- }
-
- // Over all the sources...
- for (VideoSource i : m_sources.values()) {
- int source = i.getHandle();
-
- // Get the source's subtable (if none exists, we're done)
- NetworkTable table = m_tables.get(source);
- if (table != null) {
- // Set table value
- String[] values = getSourceStreamValues(source);
- if (values.length > 0) {
- table.getEntry("streams").setStringArray(values);
- }
- }
- }
- }
-
- @SuppressWarnings("JavadocMethod")
- private static String pixelFormatToString(PixelFormat pixelFormat) {
- switch (pixelFormat) {
- case kMJPEG:
- return "MJPEG";
- case kYUYV:
- return "YUYV";
- case kRGB565:
- return "RGB565";
- case kBGR:
- return "BGR";
- case kGray:
- return "Gray";
- default:
- return "Unknown";
- }
- }
-
- /// Provide string description of video mode.
- /// The returned string is "{width}x{height} {format} {fps} fps".
- @SuppressWarnings("JavadocMethod")
- private static String videoModeToString(VideoMode mode) {
- return mode.width + "x" + mode.height + " " + pixelFormatToString(mode.pixelFormat)
- + " " + mode.fps + " fps";
- }
-
- @SuppressWarnings("JavadocMethod")
- private static String[] getSourceModeValues(int sourceHandle) {
- VideoMode[] modes = CameraServerJNI.enumerateSourceVideoModes(sourceHandle);
- String[] modeStrings = new String[modes.length];
- for (int i = 0; i < modes.length; i++) {
- modeStrings[i] = videoModeToString(modes[i]);
- }
- return modeStrings;
- }
-
- @SuppressWarnings({"JavadocMethod", "PMD.CyclomaticComplexity"})
- private static void putSourcePropertyValue(NetworkTable table, VideoEvent event, boolean isNew) {
- String name;
- String infoName;
- if (event.name.startsWith("raw_")) {
- name = "RawProperty/" + event.name;
- infoName = "RawPropertyInfo/" + event.name;
- } else {
- name = "Property/" + event.name;
- infoName = "PropertyInfo/" + event.name;
- }
-
- NetworkTableEntry entry = table.getEntry(name);
- try {
- switch (event.propertyKind) {
- case kBoolean:
- if (isNew) {
- entry.setDefaultBoolean(event.value != 0);
- } else {
- entry.setBoolean(event.value != 0);
- }
- break;
- case kInteger:
- case kEnum:
- if (isNew) {
- entry.setDefaultDouble(event.value);
- table.getEntry(infoName + "/min").setDouble(
- CameraServerJNI.getPropertyMin(event.propertyHandle));
- table.getEntry(infoName + "/max").setDouble(
- CameraServerJNI.getPropertyMax(event.propertyHandle));
- table.getEntry(infoName + "/step").setDouble(
- CameraServerJNI.getPropertyStep(event.propertyHandle));
- table.getEntry(infoName + "/default").setDouble(
- CameraServerJNI.getPropertyDefault(event.propertyHandle));
- } else {
- entry.setDouble(event.value);
- }
- break;
- case kString:
- if (isNew) {
- entry.setDefaultString(event.valueStr);
- } else {
- entry.setString(event.valueStr);
- }
- break;
- default:
- break;
- }
- } catch (VideoException ignored) {
- // ignore
- }
- }
-
- @SuppressWarnings({"JavadocMethod", "PMD.UnusedLocalVariable", "PMD.ExcessiveMethodLength",
- "PMD.NPathComplexity"})
- private CameraServer() {
- m_defaultUsbDevice = new AtomicInteger();
- m_sources = new Hashtable<>();
- m_sinks = new Hashtable<>();
- m_tables = new Hashtable<>();
- m_publishTable = NetworkTableInstance.getDefault().getTable(kPublishName);
- m_nextPort = kBasePort;
- m_addresses = new String[0];
-
- // We publish sources to NetworkTables using the following structure:
- // "/CameraPublisher/{Source.Name}/" - root
- // - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
- // - "streams" (string array): URLs that can be used to stream data
- // - "description" (string): Description of the source
- // - "connected" (boolean): Whether source is connected
- // - "mode" (string): Current video mode
- // - "modes" (string array): Available video modes
- // - "Property/{Property}" - Property values
- // - "PropertyInfo/{Property}" - Property supporting information
-
- // Listener for video events
- m_videoListener = new VideoListener(event -> {
- switch (event.kind) {
- case kSourceCreated: {
- // Create subtable for the camera
- NetworkTable table = m_publishTable.getSubTable(event.name);
- m_tables.put(event.sourceHandle, table);
- table.getEntry("source").setString(makeSourceValue(event.sourceHandle));
- table.getEntry("description").setString(
- CameraServerJNI.getSourceDescription(event.sourceHandle));
- table.getEntry("connected").setBoolean(
- CameraServerJNI.isSourceConnected(event.sourceHandle));
- table.getEntry("streams").setStringArray(getSourceStreamValues(event.sourceHandle));
- try {
- VideoMode mode = CameraServerJNI.getSourceVideoMode(event.sourceHandle);
- table.getEntry("mode").setDefaultString(videoModeToString(mode));
- table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
- } catch (VideoException ignored) {
- // Do nothing. Let the other event handlers update this if there is an error.
- }
- break;
- }
- case kSourceDestroyed: {
- NetworkTable table = m_tables.get(event.sourceHandle);
- if (table != null) {
- table.getEntry("source").setString("");
- table.getEntry("streams").setStringArray(new String[0]);
- table.getEntry("modes").setStringArray(new String[0]);
- }
- break;
- }
- case kSourceConnected: {
- NetworkTable table = m_tables.get(event.sourceHandle);
- if (table != null) {
- // update the description too (as it may have changed)
- table.getEntry("description").setString(
- CameraServerJNI.getSourceDescription(event.sourceHandle));
- table.getEntry("connected").setBoolean(true);
- }
- break;
- }
- case kSourceDisconnected: {
- NetworkTable table = m_tables.get(event.sourceHandle);
- if (table != null) {
- table.getEntry("connected").setBoolean(false);
- }
- break;
- }
- case kSourceVideoModesUpdated: {
- NetworkTable table = m_tables.get(event.sourceHandle);
- if (table != null) {
- table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
- }
- break;
- }
- case kSourceVideoModeChanged: {
- NetworkTable table = m_tables.get(event.sourceHandle);
- if (table != null) {
- table.getEntry("mode").setString(videoModeToString(event.mode));
- }
- break;
- }
- case kSourcePropertyCreated: {
- NetworkTable table = m_tables.get(event.sourceHandle);
- if (table != null) {
- putSourcePropertyValue(table, event, true);
- }
- break;
- }
- case kSourcePropertyValueUpdated: {
- NetworkTable table = m_tables.get(event.sourceHandle);
- if (table != null) {
- putSourcePropertyValue(table, event, false);
- }
- break;
- }
- case kSourcePropertyChoicesUpdated: {
- NetworkTable table = m_tables.get(event.sourceHandle);
- if (table != null) {
- try {
- String[] choices = CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
- table.getEntry("PropertyInfo/" + event.name + "/choices").setStringArray(choices);
- } catch (VideoException ignored) {
- // ignore
- }
- }
- break;
- }
- case kSinkSourceChanged:
- case kSinkCreated:
- case kSinkDestroyed:
- case kNetworkInterfacesChanged: {
- m_addresses = CameraServerJNI.getNetworkInterfaces();
- updateStreamValues();
- break;
- }
- default:
- break;
- }
- }, 0x4fff, true);
-
- // Listener for NetworkTable events
- // We don't currently support changing settings via NT due to
- // synchronization issues, so just update to current setting if someone
- // else tries to change it.
- m_tableListener = NetworkTableInstance.getDefault().addEntryListener(kPublishName + "/",
- event -> {
- String relativeKey = event.name.substring(kPublishName.length() + 1);
-
- // get source (sourceName/...)
- int subKeyIndex = relativeKey.indexOf('/');
- if (subKeyIndex == -1) {
- return;
- }
- String sourceName = relativeKey.substring(0, subKeyIndex);
- VideoSource source = m_sources.get(sourceName);
- if (source == null) {
- return;
- }
-
- // get subkey
- relativeKey = relativeKey.substring(subKeyIndex + 1);
-
- // handle standard names
- String propName;
- if ("mode".equals(relativeKey)) {
- // reset to current mode
- event.getEntry().setString(videoModeToString(source.getVideoMode()));
- return;
- } else if (relativeKey.startsWith("Property/")) {
- propName = relativeKey.substring(9);
- } else if (relativeKey.startsWith("RawProperty/")) {
- propName = relativeKey.substring(12);
- } else {
- return; // ignore
- }
-
- // everything else is a property
- VideoProperty property = source.getProperty(propName);
- switch (property.getKind()) {
- case kNone:
- return;
- case kBoolean:
- // reset to current setting
- event.getEntry().setBoolean(property.get() != 0);
- return;
- case kInteger:
- case kEnum:
- // reset to current setting
- event.getEntry().setDouble(property.get());
- return;
- case kString:
- // reset to current setting
- event.getEntry().setString(property.getString());
- return;
- default:
- return;
- }
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);
- }
-
- /**
- * Start automatically capturing images to send to the dashboard.
- *
- * <p>You should call this method to see a camera feed on the dashboard.
- * If you also want to perform vision processing on the roboRIO, use
- * getVideo() to get access to the camera images.
- *
- * <p>The first time this overload is called, it calls
- * {@link #startAutomaticCapture(int)} with device 0, creating a camera
- * named "USB Camera 0". Subsequent calls increment the device number
- * (e.g. 1, 2, etc).
- */
- public UsbCamera startAutomaticCapture() {
- UsbCamera camera = startAutomaticCapture(m_defaultUsbDevice.getAndIncrement());
- CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
- return camera;
- }
-
- /**
- * Start automatically capturing images to send to the dashboard.
- *
- * <p>This overload calls {@link #startAutomaticCapture(String, int)} with
- * a name of "USB Camera {dev}".
- *
- * @param dev The device number of the camera interface
- */
- public UsbCamera startAutomaticCapture(int dev) {
- UsbCamera camera = new UsbCamera("USB Camera " + dev, dev);
- startAutomaticCapture(camera);
- CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
- return camera;
- }
-
- /**
- * Start automatically capturing images to send to the dashboard.
- *
- * @param name The name to give the camera
- * @param dev The device number of the camera interface
- */
- public UsbCamera startAutomaticCapture(String name, int dev) {
- UsbCamera camera = new UsbCamera(name, dev);
- startAutomaticCapture(camera);
- CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
- return camera;
- }
-
- /**
- * Start automatically capturing images to send to the dashboard.
- *
- * @param name The name to give the camera
- * @param path The device path (e.g. "/dev/video0") of the camera
- */
- public UsbCamera startAutomaticCapture(String name, String path) {
- UsbCamera camera = new UsbCamera(name, path);
- startAutomaticCapture(camera);
- CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
- return camera;
- }
-
- /**
- * Start automatically capturing images to send to the dashboard from
- * an existing camera.
- *
- * @param camera Camera
- */
- public void startAutomaticCapture(VideoSource camera) {
- addCamera(camera);
- VideoSink server = addServer("serve_" + camera.getName());
- server.setSource(camera);
- }
-
- /**
- * Adds an Axis IP camera.
- *
- * <p>This overload calls {@link #addAxisCamera(String, String)} with
- * name "Axis Camera".
- *
- * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
- */
- public AxisCamera addAxisCamera(String host) {
- return addAxisCamera("Axis Camera", host);
- }
-
- /**
- * Adds an Axis IP camera.
- *
- * <p>This overload calls {@link #addAxisCamera(String, String[])} with
- * name "Axis Camera".
- *
- * @param hosts Array of Camera host IPs/DNS names
- */
- public AxisCamera addAxisCamera(String[] hosts) {
- return addAxisCamera("Axis Camera", hosts);
- }
-
- /**
- * Adds an Axis IP camera.
- *
- * @param name The name to give the camera
- * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
- */
- public AxisCamera addAxisCamera(String name, String host) {
- AxisCamera camera = new AxisCamera(name, host);
- // Create a passthrough MJPEG server for USB access
- startAutomaticCapture(camera);
- CameraServerSharedStore.getCameraServerShared().reportAxisCamera(camera.getHandle());
- return camera;
- }
-
- /**
- * Adds an Axis IP camera.
- *
- * @param name The name to give the camera
- * @param hosts Array of Camera host IPs/DNS names
- */
- public AxisCamera addAxisCamera(String name, String[] hosts) {
- AxisCamera camera = new AxisCamera(name, hosts);
- // Create a passthrough MJPEG server for USB access
- startAutomaticCapture(camera);
- CameraServerSharedStore.getCameraServerShared().reportAxisCamera(camera.getHandle());
- return camera;
- }
-
- /**
- * Get OpenCV access to the primary camera feed. This allows you to
- * get images from the camera for image processing on the roboRIO.
- *
- * <p>This is only valid to call after a camera feed has been added
- * with startAutomaticCapture() or addServer().
- */
- public CvSink getVideo() {
- VideoSource source;
- synchronized (this) {
- if (m_primarySourceName == null) {
- throw new VideoException("no camera available");
- }
- source = m_sources.get(m_primarySourceName);
- }
- if (source == null) {
- throw new VideoException("no camera available");
- }
- return getVideo(source);
- }
-
- /**
- * Get OpenCV access to the specified camera. This allows you to get
- * images from the camera for image processing on the roboRIO.
- *
- * @param camera Camera (e.g. as returned by startAutomaticCapture).
- */
- public CvSink getVideo(VideoSource camera) {
- String name = "opencv_" + camera.getName();
-
- synchronized (this) {
- VideoSink sink = m_sinks.get(name);
- if (sink != null) {
- VideoSink.Kind kind = sink.getKind();
- if (kind != VideoSink.Kind.kCv) {
- throw new VideoException("expected OpenCV sink, but got " + kind);
- }
- return (CvSink) sink;
- }
- }
-
- CvSink newsink = new CvSink(name);
- newsink.setSource(camera);
- addServer(newsink);
- return newsink;
- }
-
- /**
- * Get OpenCV access to the specified camera. This allows you to get
- * images from the camera for image processing on the roboRIO.
- *
- * @param name Camera name
- */
- public CvSink getVideo(String name) {
- VideoSource source;
- synchronized (this) {
- source = m_sources.get(name);
- if (source == null) {
- throw new VideoException("could not find camera " + name);
- }
- }
- return getVideo(source);
- }
-
- /**
- * Create a MJPEG stream with OpenCV input. This can be called to pass custom
- * annotated images to the dashboard.
- *
- * @param name Name to give the stream
- * @param width Width of the image being sent
- * @param height Height of the image being sent
- */
- public CvSource putVideo(String name, int width, int height) {
- CvSource source = new CvSource(name, VideoMode.PixelFormat.kMJPEG, width, height, 30);
- startAutomaticCapture(source);
- return source;
- }
-
- /**
- * Adds a MJPEG server at the next available port.
- *
- * @param name Server name
- */
- public MjpegServer addServer(String name) {
- int port;
- synchronized (this) {
- port = m_nextPort;
- m_nextPort++;
- }
- return addServer(name, port);
- }
-
- /**
- * Adds a MJPEG server.
- *
- * @param name Server name
- */
- public MjpegServer addServer(String name, int port) {
- MjpegServer server = new MjpegServer(name, port);
- addServer(server);
- return server;
- }
-
- /**
- * Adds an already created server.
- *
- * @param server Server
- */
- public void addServer(VideoSink server) {
- synchronized (this) {
- m_sinks.put(server.getName(), server);
- }
- }
-
- /**
- * Removes a server by name.
- *
- * @param name Server name
- */
- public void removeServer(String name) {
- synchronized (this) {
- m_sinks.remove(name);
- }
- }
-
- /**
- * Get server for the primary camera feed.
- *
- * <p>This is only valid to call after a camera feed has been added
- * with startAutomaticCapture() or addServer().
- */
- public VideoSink getServer() {
- synchronized (this) {
- if (m_primarySourceName == null) {
- throw new VideoException("no camera available");
- }
- return getServer("serve_" + m_primarySourceName);
- }
- }
-
- /**
- * Gets a server by name.
- *
- * @param name Server name
- */
- public VideoSink getServer(String name) {
- synchronized (this) {
- return m_sinks.get(name);
- }
- }
-
- /**
- * Adds an already created camera.
- *
- * @param camera Camera
- */
- public void addCamera(VideoSource camera) {
- String name = camera.getName();
- synchronized (this) {
- if (m_primarySourceName == null) {
- m_primarySourceName = name;
- }
- m_sources.put(name, camera);
- }
- }
-
- /**
- * Removes a camera by name.
- *
- * @param name Camera name
- */
- public void removeCamera(String name) {
- synchronized (this) {
- m_sources.remove(name);
- }
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java
index 8fbefd8..f48fb63 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java
@@ -1,61 +1,79 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import edu.wpi.first.hal.CompressorJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.hal.util.AllocationException;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
- * Class for operating a compressor connected to a PCM (Pneumatic Control Module). The PCM will
- * automatically run in closed loop mode by default whenever a {@link Solenoid} object is created.
- * For most cases, a Compressor object does not need to be instantiated or used in a robot program.
- * This class is only required in cases where the robot program needs a more detailed status of the
- * compressor or to enable/disable closed loop control.
+ * Class for operating a compressor connected to a pneumatics module. The module will automatically
+ * run in closed loop mode by default whenever a {@link Solenoid} object is created. For most cases,
+ * a Compressor object does not need to be instantiated or used in a robot program. This class is
+ * only required in cases where the robot program needs a more detailed status of the compressor or
+ * to enable/disable closed loop control.
*
* <p>Note: you cannot operate the compressor directly from this class as doing so would circumvent
* the safety provided by using the pressure switch and closed loop control. You can only turn off
* closed loop control, thereby stopping the compressor from operating.
*/
public class Compressor implements Sendable, AutoCloseable {
- private int m_compressorHandle;
- private byte m_module;
+ private PneumaticsBase m_module;
/**
- * Makes a new instance of the compressor using the provided CAN device ID. Use this constructor
- * when you have more than one PCM.
+ * Constructs a compressor for a specified module and type.
*
- * @param module The PCM CAN device ID (0 - 62 inclusive)
+ * @param module The module ID to use.
+ * @param moduleType The module type to use.
*/
- public Compressor(int module) {
- m_module = (byte) module;
+ public Compressor(int module, PneumaticsModuleType moduleType) {
+ m_module = PneumaticsBase.getForType(module, moduleType);
+ boolean allocatedCompressor = false;
+ boolean successfulCompletion = false;
- m_compressorHandle = CompressorJNI.initializeCompressor((byte) module);
+ try {
+ if (!m_module.reserveCompressor()) {
+ throw new AllocationException("Compressor already allocated");
+ }
- HAL.report(tResourceType.kResourceType_Compressor, module + 1);
- SendableRegistry.addLW(this, "Compressor", module);
+ allocatedCompressor = true;
+
+ m_module.setClosedLoopControl(true);
+
+ HAL.report(tResourceType.kResourceType_Compressor, module + 1);
+ SendableRegistry.addLW(this, "Compressor", module);
+ successfulCompletion = true;
+
+ } finally {
+ if (!successfulCompletion) {
+ if (allocatedCompressor) {
+ m_module.unreserveCompressor();
+ }
+ m_module.close();
+ }
+ }
}
/**
- * Makes a new instance of the compressor using the default PCM ID of 0.
+ * Constructs a compressor for a default module and specified type.
*
- * <p>Additional modules can be supported by making a new instance and {@link #Compressor(int)
- * specifying the CAN ID.}
+ * @param moduleType The module type to use.
*/
- public Compressor() {
- this(SensorUtil.getDefaultSolenoidModule());
+ public Compressor(PneumaticsModuleType moduleType) {
+ this(PneumaticsBase.getDefaultForType(moduleType), moduleType);
}
@Override
public void close() {
SendableRegistry.remove(this);
+ m_module.unreserveCompressor();
+ m_module.close();
+ m_module = null;
}
/**
@@ -86,7 +104,7 @@
* @return true if the compressor is on
*/
public boolean enabled() {
- return CompressorJNI.getCompressor(m_compressorHandle);
+ return m_module.getCompressor();
}
/**
@@ -95,7 +113,7 @@
* @return true if the pressure is low
*/
public boolean getPressureSwitchValue() {
- return CompressorJNI.getCompressorPressureSwitch(m_compressorHandle);
+ return m_module.getPressureSwitch();
}
/**
@@ -104,7 +122,7 @@
* @return current consumed by the compressor in amps
*/
public double getCompressorCurrent() {
- return CompressorJNI.getCompressorCurrent(m_compressorHandle);
+ return m_module.getCompressorCurrent();
}
/**
@@ -113,7 +131,7 @@
* @param on if true sets the compressor to be in closed loop control mode (default)
*/
public void setClosedLoopControl(boolean on) {
- CompressorJNI.setCompressorClosedLoopControl(m_compressorHandle, on);
+ m_module.setClosedLoopControl(on);
}
/**
@@ -122,99 +140,15 @@
* @return true if compressor is operating on closed-loop mode
*/
public boolean getClosedLoopControl() {
- return CompressorJNI.getCompressorClosedLoopControl(m_compressorHandle);
- }
-
- /**
- * If PCM is in fault state : Compressor Drive is disabled due to compressor current being too
- * high.
- *
- * @return true if PCM is in fault state.
- */
- public boolean getCompressorCurrentTooHighFault() {
- return CompressorJNI.getCompressorCurrentTooHighFault(m_compressorHandle);
- }
-
- /**
- * If PCM sticky fault is set : Compressor is disabled due to compressor current being too
- * high.
- *
- * @return true if PCM sticky fault is set.
- */
- public boolean getCompressorCurrentTooHighStickyFault() {
- return CompressorJNI.getCompressorCurrentTooHighStickyFault(m_compressorHandle);
- }
-
- /**
- * If PCM sticky fault is set : Compressor output appears to be shorted.
- *
- * @return true if PCM sticky fault is set.
- */
- public boolean getCompressorShortedStickyFault() {
- return CompressorJNI.getCompressorShortedStickyFault(m_compressorHandle);
- }
-
- /**
- * If PCM is in fault state : Compressor output appears to be shorted.
- *
- * @return true if PCM is in fault state.
- */
- public boolean getCompressorShortedFault() {
- return CompressorJNI.getCompressorShortedFault(m_compressorHandle);
- }
-
- /**
- * If PCM sticky fault is set : Compressor does not appear to be wired, i.e. compressor is not
- * drawing enough current.
- *
- * @return true if PCM sticky fault is set.
- */
- public boolean getCompressorNotConnectedStickyFault() {
- return CompressorJNI.getCompressorNotConnectedStickyFault(m_compressorHandle);
- }
-
- /**
- * If PCM is in fault state : Compressor does not appear to be wired, i.e. compressor is not
- * drawing enough current.
- *
- * @return true if PCM is in fault state.
- */
- public boolean getCompressorNotConnectedFault() {
- return CompressorJNI.getCompressorNotConnectedFault(m_compressorHandle);
- }
-
- /**
- * Clear ALL sticky faults inside PCM that Compressor is wired to.
- *
- * <p>If a sticky fault is set, then it will be persistently cleared. The compressor might
- * momentarily disable while the flags are being cleared. Doo not call this method too
- * frequently, otherwise normal compressor functionality may be prevented.
- *
- * <p>If no sticky faults are set then this call will have no effect.
- */
- public void clearAllPCMStickyFaults() {
- CompressorJNI.clearAllPCMStickyFaults(m_module);
- }
-
- /**
- * Gets the module number (CAN ID).
- *
- * @return Module number
- */
- public int getModule() {
- return m_module;
+ return m_module.getClosedLoopControl();
}
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Compressor");
- builder.addBooleanProperty("Enabled", this::enabled, value -> {
- if (value) {
- start();
- } else {
- stop();
- }
- });
+ builder.addBooleanProperty(
+ "Closed Loop Control", this::getClosedLoopControl, this::setClosedLoopControl);
+ builder.addBooleanProperty("Enabled", this::enabled, null);
builder.addBooleanProperty("Pressure switch", this::getPressureSwitchValue, null);
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Controller.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Controller.java
index 31d50d8..886050b 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Controller.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Controller.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -16,9 +13,7 @@
*/
@Deprecated(since = "2020", forRemoval = true)
public interface Controller {
- /**
- * Allows the control loop to run.
- */
+ /** Allows the control loop to run. */
void enable();
/**
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Counter.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Counter.java
index 0a26810..d445e9f 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Counter.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Counter.java
@@ -1,58 +1,44 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import static java.util.Objects.requireNonNull;
import edu.wpi.first.hal.CounterJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
+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.AnalogTriggerOutput.AnalogTriggerType;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
-import static java.util.Objects.requireNonNull;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
/**
* Class for counting the number of ticks on a digital input channel.
*
* <p>This is a general purpose class for counting repetitive events. It can return the number of
- * counts, the period of the most recent cycle, and detect when the signal being counted has
- * stopped by supplying a maximum cycle time.
+ * counts, the period of the most recent cycle, and detect when the signal being counted has stopped
+ * by supplying a maximum cycle time.
*
* <p>All counters will immediately start counting - reset() them if you need them to be zeroed
* before use.
*/
-public class Counter implements CounterBase, PIDSource, Sendable, AutoCloseable {
- /**
- * Mode determines how and what the counter counts.
- */
+public class Counter implements CounterBase, Sendable, AutoCloseable {
+ /** Mode determines how and what the counter counts. */
public enum Mode {
- /**
- * mode: two pulse.
- */
+ /** mode: two pulse. */
kTwoPulse(0),
- /**
- * mode: semi period.
- */
+ /** mode: semi period. */
kSemiperiod(1),
- /**
- * mode: pulse length.
- */
+ /** mode: pulse length. */
kPulseLength(2),
- /**
- * mode: external direction.
- */
+ /** mode: external direction. */
kExternalDirection(3);
- @SuppressWarnings("MemberName")
public final int value;
Mode(int value) {
@@ -64,13 +50,14 @@
protected DigitalSource m_downSource; // /< What makes the counter count down.
private boolean m_allocatedUpSource;
private boolean m_allocatedDownSource;
- private int m_counter; // /< The FPGA counter object.
+ int m_counter; // /< The FPGA counter object.
private int m_index; // /< The index of this counter.
- private PIDSourceType m_pidSource;
private double m_distancePerPulse; // distance of travel for each tick
/**
* Create an instance of a counter with the given mode.
+ *
+ * @param mode The counter mode.
*/
public Counter(final Mode mode) {
ByteBuffer index = ByteBuffer.allocateDirect(4);
@@ -135,12 +122,15 @@
* <p>The counter will start counting immediately.
*
* @param encodingType which edges to count
- * @param upSource first source to count
- * @param downSource second source for direction
- * @param inverted true to invert the count
+ * @param upSource first source to count
+ * @param downSource second source for direction
+ * @param inverted true to invert the count
*/
- public Counter(EncodingType encodingType, DigitalSource upSource, DigitalSource downSource,
- boolean inverted) {
+ public Counter(
+ EncodingType encodingType,
+ DigitalSource upSource,
+ DigitalSource downSource,
+ boolean inverted) {
this(Mode.kExternalDirection);
requireNonNullParam(encodingType, "encodingType", "Counter");
@@ -229,15 +219,15 @@
m_allocatedUpSource = false;
}
m_upSource = source;
- CounterJNI.setCounterUpSource(m_counter, source.getPortHandleForRouting(),
- source.getAnalogTriggerTypeForRouting());
+ CounterJNI.setCounterUpSource(
+ m_counter, source.getPortHandleForRouting(), source.getAnalogTriggerTypeForRouting());
}
/**
* Set the up counting source to be an analog trigger.
*
* @param analogTrigger The analog trigger object that is used for the Up Source
- * @param triggerType The analog trigger output that will trigger the counter.
+ * @param triggerType The analog trigger output that will trigger the counter.
*/
public void setUpSource(AnalogTrigger analogTrigger, AnalogTriggerType triggerType) {
requireNonNullParam(analogTrigger, "analogTrigger", "setUpSource");
@@ -251,7 +241,7 @@
* Set the edge sensitivity on an up counting source. Set the up source to either detect rising
* edges or falling edges.
*
- * @param risingEdge true to count rising edge
+ * @param risingEdge true to count rising edge
* @param fallingEdge true to count falling edge
*/
public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
@@ -261,9 +251,7 @@
CounterJNI.setCounterUpSourceEdge(m_counter, risingEdge, fallingEdge);
}
- /**
- * Disable the up counting source to the counter.
- */
+ /** Disable the up counting source to the counter. */
public void clearUpSource() {
if (m_upSource != null && m_allocatedUpSource) {
m_upSource.close();
@@ -298,8 +286,8 @@
m_downSource.close();
m_allocatedDownSource = false;
}
- CounterJNI.setCounterDownSource(m_counter, source.getPortHandleForRouting(),
- source.getAnalogTriggerTypeForRouting());
+ CounterJNI.setCounterDownSource(
+ m_counter, source.getPortHandleForRouting(), source.getAnalogTriggerTypeForRouting());
m_downSource = source;
}
@@ -307,7 +295,7 @@
* Set the down counting source to be an analog trigger.
*
* @param analogTrigger The analog trigger object that is used for the Down Source
- * @param triggerType The analog trigger output that will trigger the counter.
+ * @param triggerType The analog trigger output that will trigger the counter.
*/
public void setDownSource(AnalogTrigger analogTrigger, AnalogTriggerType triggerType) {
requireNonNullParam(analogTrigger, "analogTrigger", "setDownSource");
@@ -321,7 +309,7 @@
* Set the edge sensitivity on a down counting source. Set the down source to either detect rising
* edges or falling edges.
*
- * @param risingEdge true to count the rising edge
+ * @param risingEdge true to count the rising edge
* @param fallingEdge true to count the falling edge
*/
public void setDownSourceEdge(boolean risingEdge, boolean fallingEdge) {
@@ -330,9 +318,7 @@
CounterJNI.setCounterDownSourceEdge(m_counter, risingEdge, fallingEdge);
}
- /**
- * Disable the down counting source to the counter.
- */
+ /** Disable the down counting source to the counter. */
public void clearDownSource() {
if (m_downSource != null && m_allocatedDownSource) {
m_downSource.close();
@@ -373,7 +359,7 @@
* is most useful for direction sensitive gear tooth sensors.
*
* @param threshold The pulse length beyond which the counter counts the opposite direction. Units
- * are seconds.
+ * are seconds.
*/
public void setPulseLengthMode(double threshold) {
CounterJNI.setCounterPulseLengthMode(m_counter, threshold);
@@ -525,39 +511,6 @@
m_distancePerPulse = distancePerPulse;
}
- /**
- * Set which parameter of the encoder you are using as a process control variable. The counter
- * class supports the rate and distance parameters.
- *
- * @param pidSource An enum to select the parameter.
- */
- @Override
- public void setPIDSourceType(PIDSourceType pidSource) {
- requireNonNullParam(pidSource, "pidSource", "setPIDSourceType");
- if (pidSource != PIDSourceType.kDisplacement && pidSource != PIDSourceType.kRate) {
- throw new IllegalArgumentException("PID Source parameter was not valid type: " + pidSource);
- }
-
- m_pidSource = pidSource;
- }
-
- @Override
- public PIDSourceType getPIDSourceType() {
- return m_pidSource;
- }
-
- @Override
- public double pidGet() {
- switch (m_pidSource) {
- case kDisplacement:
- return getDistance();
- case kRate:
- return getRate();
- default:
- return 0.0;
- }
- }
-
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Counter");
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/CounterBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/CounterBase.java
index 9d1d6b7..735b893 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/CounterBase.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/CounterBase.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -16,24 +13,15 @@
* before use.
*/
public interface CounterBase {
- /**
- * The number of edges for the counterbase to increment or decrement on.
- */
+ /** The number of edges for the counterbase to increment or decrement on. */
enum EncodingType {
- /**
- * Count only the rising edge.
- */
+ /** Count only the rising edge. */
k1X(0),
- /**
- * Count both the rising and falling edge.
- */
+ /** Count both the rising and falling edge. */
k2X(1),
- /**
- * Count rising and falling on both channels.
- */
+ /** Count rising and falling on both channels. */
k4X(2);
- @SuppressWarnings("MemberName")
public final int value;
EncodingType(int value) {
@@ -48,9 +36,7 @@
*/
int get();
- /**
- * Reset the count to zero.
- */
+ /** Reset the count to zero. */
void reset();
/**
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMA.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMA.java
new file mode 100644
index 0000000..a919da5
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMA.java
@@ -0,0 +1,110 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.hal.DMAJNI;
+import edu.wpi.first.wpilibj.motorcontrol.PWMMotorController;
+
+public class DMA implements AutoCloseable {
+ final int m_dmaHandle;
+
+ public DMA() {
+ m_dmaHandle = DMAJNI.initialize();
+ }
+
+ @Override
+ public void close() {
+ DMAJNI.free(m_dmaHandle);
+ }
+
+ public void setPause(boolean pause) {
+ DMAJNI.setPause(m_dmaHandle, pause);
+ }
+
+ public void setTimedTrigger(double periodSeconds) {
+ DMAJNI.setTimedTrigger(m_dmaHandle, periodSeconds);
+ }
+
+ public void setTimedTriggerCycles(int cycles) {
+ DMAJNI.setTimedTriggerCycles(m_dmaHandle, cycles);
+ }
+
+ public void addEncoder(Encoder encoder) {
+ DMAJNI.addEncoder(m_dmaHandle, encoder.m_encoder);
+ }
+
+ public void addEncoderPeriod(Encoder encoder) {
+ DMAJNI.addEncoderPeriod(m_dmaHandle, encoder.m_encoder);
+ }
+
+ public void addCounter(Counter counter) {
+ DMAJNI.addCounter(m_dmaHandle, counter.m_counter);
+ }
+
+ public void addCounterPeriod(Counter counter) {
+ DMAJNI.addCounterPeriod(m_dmaHandle, counter.m_counter);
+ }
+
+ public void addDigitalSource(DigitalSource digitalSource) {
+ DMAJNI.addDigitalSource(m_dmaHandle, digitalSource.getPortHandleForRouting());
+ }
+
+ public void addDutyCycle(DutyCycle dutyCycle) {
+ DMAJNI.addDutyCycle(m_dmaHandle, dutyCycle.m_handle);
+ }
+
+ public void addAnalogInput(AnalogInput analogInput) {
+ DMAJNI.addAnalogInput(m_dmaHandle, analogInput.m_port);
+ }
+
+ public void addAveragedAnalogInput(AnalogInput analogInput) {
+ DMAJNI.addAveragedAnalogInput(m_dmaHandle, analogInput.m_port);
+ }
+
+ public void addAnalogAccumulator(AnalogInput analogInput) {
+ DMAJNI.addAnalogAccumulator(m_dmaHandle, analogInput.m_port);
+ }
+
+ /**
+ * Sets an external DMA trigger.
+ *
+ * @param source the source to trigger from.
+ * @param rising trigger on rising edge.
+ * @param falling trigger on falling edge.
+ * @return the index of the trigger
+ */
+ public int setExternalTrigger(DigitalSource source, boolean rising, boolean falling) {
+ return DMAJNI.setExternalTrigger(
+ m_dmaHandle,
+ source.getPortHandleForRouting(),
+ source.getAnalogTriggerTypeForRouting(),
+ rising,
+ falling);
+ }
+
+ public int setPwmEdgeTrigger(PWMMotorController pwm, boolean rising, boolean falling) {
+ return DMAJNI.setExternalTrigger(m_dmaHandle, pwm.getPwmHandle(), 0, rising, falling);
+ }
+
+ public int setPwmEdgeTrigger(PWM pwm, boolean rising, boolean falling) {
+ return DMAJNI.setExternalTrigger(m_dmaHandle, pwm.getHandle(), 0, rising, falling);
+ }
+
+ public void clearSensors() {
+ DMAJNI.clearSensors(m_dmaHandle);
+ }
+
+ public void clearExternalTriggers() {
+ DMAJNI.clearExternalTriggers(m_dmaHandle);
+ }
+
+ public void start(int queueDepth) {
+ DMAJNI.startDMA(m_dmaHandle, queueDepth);
+ }
+
+ public void stop() {
+ DMAJNI.stopDMA(m_dmaHandle);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMASample.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMASample.java
new file mode 100644
index 0000000..1055dbc
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMASample.java
@@ -0,0 +1,126 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.hal.AnalogJNI;
+import edu.wpi.first.hal.DMAJNISample;
+
+public class DMASample {
+ public enum DMAReadStatus {
+ kOk(1),
+ kTimeout(2),
+ kError(3);
+
+ private final int value;
+
+ DMAReadStatus(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ /**
+ * Constructs a DMAReadStatus from a raw value.
+ *
+ * @param value raw value
+ * @return enum value
+ */
+ public static DMAReadStatus getValue(int value) {
+ if (value == 1) {
+ return kOk;
+ } else if (value == 2) {
+ return kTimeout;
+ }
+ return kError;
+ }
+ }
+
+ private final DMAJNISample m_dmaSample = new DMAJNISample();
+
+ public DMAReadStatus update(DMA dma, double timeoutSeconds) {
+ return DMAReadStatus.getValue(m_dmaSample.update(dma.m_dmaHandle, timeoutSeconds));
+ }
+
+ public int getCaptureSize() {
+ return m_dmaSample.getCaptureSize();
+ }
+
+ public int getTriggerChannels() {
+ return m_dmaSample.getTriggerChannels();
+ }
+
+ public int getRemaining() {
+ return m_dmaSample.getRemaining();
+ }
+
+ public long getTime() {
+ return m_dmaSample.getTime();
+ }
+
+ public double getTimeStamp() {
+ return getTime() * 1.0e-6;
+ }
+
+ public int getEncoderRaw(Encoder encoder) {
+ return m_dmaSample.getEncoder(encoder.m_encoder);
+ }
+
+ /**
+ * Gets the scaled encoder distance for this sample.
+ *
+ * @param encoder the encoder to use to read
+ * @return the distance
+ */
+ public double getEncoderDistance(Encoder encoder) {
+ double val = getEncoderRaw(encoder);
+ val *= encoder.getDecodingScaleFactor();
+ val *= encoder.getDistancePerPulse();
+ return val;
+ }
+
+ public int getEncoderPeriodRaw(Encoder encoder) {
+ return m_dmaSample.getEncoderPeriod(encoder.m_encoder);
+ }
+
+ public int getCounter(Counter counter) {
+ return m_dmaSample.getCounter(counter.m_counter);
+ }
+
+ public int getCounterPeriod(Counter counter) {
+ return m_dmaSample.getCounterPeriod(counter.m_counter);
+ }
+
+ public boolean getDigitalSource(DigitalSource digitalSource) {
+ return m_dmaSample.getDigitalSource(digitalSource.getPortHandleForRouting());
+ }
+
+ public int getAnalogInputRaw(AnalogInput analogInput) {
+ return m_dmaSample.getAnalogInput(analogInput.m_port);
+ }
+
+ public double getAnalogInputVoltage(AnalogInput analogInput) {
+ return AnalogJNI.getAnalogValueToVolts(analogInput.m_port, getAnalogInputRaw(analogInput));
+ }
+
+ public int getAveragedAnalogInputRaw(AnalogInput analogInput) {
+ return m_dmaSample.getAnalogInputAveraged(analogInput.m_port);
+ }
+
+ public double getAveragedAnalogInputVoltage(AnalogInput analogInput) {
+ return AnalogJNI.getAnalogValueToVolts(
+ analogInput.m_port, getAveragedAnalogInputRaw(analogInput));
+ }
+
+ public int getDutyCycleOutputRaw(DutyCycle dutyCycle) {
+ return m_dmaSample.getDutyCycleOutput(dutyCycle.m_handle);
+ }
+
+ public double getDutyCycleOutput(DutyCycle dutyCycle) {
+ return m_dmaSample.getDutyCycleOutput(dutyCycle.m_handle)
+ / (double) dutyCycle.getOutputScaleFactor();
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMC60.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMC60.java
deleted file mode 100644
index 0feeebb..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DMC60.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Digilent DMC 60 Speed Controller.
- *
- * <p>Note that the DMC uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the DMC 60 User Manual
- * available from Digilent.
- *
- * <p><ul>
- * <li>2.004ms = full "forward"
- * <li>1.520ms = the "high end" of the deadband range
- * <li>1.500ms = center of the deadband range (off)
- * <li>1.480ms = the "low end" of the deadband range
- * <li>0.997ms = full "reverse"
- * </ul>
- */
-public class DMC60 extends PWMSpeedController {
- /**
- * Constructor.
- *
- * @param channel The PWM channel that the DMC60 is attached to. 0-9 are
- * on-board, 10-19 are on the MXP port
- */
- public DMC60(final int channel) {
- super(channel);
-
- setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_DigilentDMC60, getChannel() + 1);
- SendableRegistry.setName(this, "DMC60", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DSControlWord.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DSControlWord.java
new file mode 100644
index 0000000..016abc7
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DSControlWord.java
@@ -0,0 +1,127 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.hal.ControlWord;
+import edu.wpi.first.hal.HAL;
+
+/** A wrapper around Driver Station control word. */
+public class DSControlWord {
+ private final ControlWord m_controlWord = new ControlWord();
+
+ /**
+ * DSControlWord constructor.
+ *
+ * <p>Upon construction, the current Driver Station control word is read and stored internally.
+ */
+ public DSControlWord() {
+ update();
+ }
+
+ /** Update internal Driver Station control word. */
+ public void update() {
+ HAL.getControlWord(m_controlWord);
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be enabled.
+ *
+ * @return True if the robot is enabled, false otherwise.
+ */
+ public boolean isEnabled() {
+ return m_controlWord.getEnabled() && m_controlWord.getDSAttached();
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be disabled.
+ *
+ * @return True if the robot should be disabled, false otherwise.
+ */
+ public boolean isDisabled() {
+ return !isEnabled();
+ }
+
+ /**
+ * Gets a value indicating whether the Robot is e-stopped.
+ *
+ * @return True if the robot is e-stopped, false otherwise.
+ */
+ public boolean isEStopped() {
+ return m_controlWord.getEStop();
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be running in
+ * autonomous mode.
+ *
+ * @return True if autonomous mode should be enabled, false otherwise.
+ */
+ public boolean isAutonomous() {
+ return m_controlWord.getAutonomous();
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be running in
+ * autonomous mode and enabled.
+ *
+ * @return True if autonomous should be set and the robot should be enabled.
+ */
+ public boolean isAutonomousEnabled() {
+ return m_controlWord.getAutonomous()
+ && m_controlWord.getEnabled()
+ && m_controlWord.getDSAttached();
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be running in
+ * operator-controlled mode.
+ *
+ * @return True if operator-controlled mode should be enabled, false otherwise.
+ */
+ public boolean isTeleop() {
+ return !(isAutonomous() || isTest());
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be running in
+ * operator-controller mode and enabled.
+ *
+ * @return True if operator-controlled mode should be set and the robot should be enabled.
+ */
+ public boolean isTeleopEnabled() {
+ return !m_controlWord.getAutonomous()
+ && !m_controlWord.getTest()
+ && m_controlWord.getEnabled()
+ && m_controlWord.getDSAttached();
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be running in test
+ * mode.
+ *
+ * @return True if test mode should be enabled, false otherwise.
+ */
+ public boolean isTest() {
+ return m_controlWord.getTest();
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station is attached.
+ *
+ * @return True if Driver Station is attached, false otherwise.
+ */
+ public boolean isDSAttached() {
+ return m_controlWord.getDSAttached();
+ }
+
+ /**
+ * Gets if the driver station attached to a Field Management System.
+ *
+ * @return true if the robot is competing on a field being controlled by a Field Management System
+ */
+ public boolean isFMSAttached() {
+ return m_controlWord.getFMSAttached();
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Debouncer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Debouncer.java
new file mode 100644
index 0000000..cef85aa
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Debouncer.java
@@ -0,0 +1,79 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+/**
+ * A simple debounce filter for boolean streams. Requires that the boolean change value from
+ * baseline for a specified period of time before the filtered value changes.
+ */
+public class Debouncer {
+ public enum DebounceType {
+ kRising,
+ kFalling,
+ kBoth
+ }
+
+ private final Timer m_timer = new Timer();
+ private final double m_debounceTime;
+ private final DebounceType m_debounceType;
+ private boolean m_baseline;
+
+ /**
+ * Creates a new Debouncer.
+ *
+ * @param debounceTime The number of seconds the value must change from baseline for the filtered
+ * value to change.
+ * @param type Which type of state change the debouncing will be performed on.
+ */
+ public Debouncer(double debounceTime, DebounceType type) {
+ m_debounceTime = debounceTime;
+ m_debounceType = type;
+ m_timer.start();
+
+ switch (m_debounceType) {
+ case kBoth: // fall-through
+ case kRising:
+ m_baseline = false;
+ break;
+ case kFalling:
+ m_baseline = true;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid debounce type!");
+ }
+ }
+
+ /**
+ * Creates a new Debouncer. Baseline value defaulted to "false."
+ *
+ * @param debounceTime The number of seconds the value must change from baseline for the filtered
+ * value to change.
+ */
+ public Debouncer(double debounceTime) {
+ this(debounceTime, DebounceType.kRising);
+ }
+
+ /**
+ * Applies the debouncer to the input stream.
+ *
+ * @param input The current value of the input stream.
+ * @return The debounced value of the input stream.
+ */
+ public boolean calculate(boolean input) {
+ if (input == m_baseline) {
+ m_timer.reset();
+ }
+
+ if (m_timer.hasElapsed(m_debounceTime)) {
+ if (m_debounceType == DebounceType.kBoth) {
+ m_baseline = input;
+ m_timer.reset();
+ }
+ return input;
+ } else {
+ return m_baseline;
+ }
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalGlitchFilter.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalGlitchFilter.java
index 10155cc..abcc67b 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalGlitchFilter.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalGlitchFilter.java
@@ -1,20 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
import edu.wpi.first.hal.DigitalGlitchFilterJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Class to enable glitch filtering on a set of digital inputs. This class will manage adding and
@@ -22,11 +19,10 @@
* that an input must remain high or low before it is classified as high or low.
*/
public class DigitalGlitchFilter implements Sendable, AutoCloseable {
- /**
- * Configures the Digital Glitch Filter to its default settings.
- */
+ /** Configures the Digital Glitch Filter to its default settings. */
public DigitalGlitchFilter() {
- synchronized (m_mutex) {
+ m_mutex.lock();
+ try {
int index = 0;
while (m_filterAllocated[index] && index < m_filterAllocated.length) {
index++;
@@ -34,10 +30,11 @@
if (index != m_filterAllocated.length) {
m_channelIndex = index;
m_filterAllocated[index] = true;
- HAL.report(tResourceType.kResourceType_DigitalGlitchFilter,
- m_channelIndex + 1, 0);
+ HAL.report(tResourceType.kResourceType_DigitalGlitchFilter, m_channelIndex + 1, 0);
SendableRegistry.addLW(this, "DigitalGlitchFilter", index);
}
+ } finally {
+ m_mutex.unlock();
}
}
@@ -45,9 +42,13 @@
public void close() {
SendableRegistry.remove(this);
if (m_channelIndex >= 0) {
- synchronized (m_mutex) {
+ m_mutex.lock();
+ try {
m_filterAllocated[m_channelIndex] = false;
+ } finally {
+ m_mutex.unlock();
}
+
m_channelIndex = -1;
}
}
@@ -62,8 +63,8 @@
int selected = DigitalGlitchFilterJNI.getFilterSelect(input.getPortHandleForRouting());
if (selected != channelIndex) {
- throw new IllegalStateException("DigitalGlitchFilterJNI.setFilterSelect("
- + channelIndex + ") failed -> " + selected);
+ throw new IllegalStateException(
+ "DigitalGlitchFilterJNI.setFilterSelect(" + channelIndex + ") failed -> " + selected);
}
}
}
@@ -143,8 +144,7 @@
* @param nanoseconds The number of nanoseconds.
*/
public void setPeriodNanoSeconds(long nanoseconds) {
- int fpgaCycles = (int) (nanoseconds * SensorUtil.kSystemClockTicksPerMicrosecond / 4
- / 1000);
+ int fpgaCycles = (int) (nanoseconds * SensorUtil.kSystemClockTicksPerMicrosecond / 4 / 1000);
setPeriodCycles(fpgaCycles);
}
@@ -167,14 +167,11 @@
public long getPeriodNanoSeconds() {
int fpgaCycles = getPeriodCycles();
- return (long) fpgaCycles * 1000L
- / (long) (SensorUtil.kSystemClockTicksPerMicrosecond / 4);
+ return (long) fpgaCycles * 1000L / (long) (SensorUtil.kSystemClockTicksPerMicrosecond / 4);
}
@Override
- @SuppressWarnings("PMD.UnusedFormalParameter")
- public void initSendable(SendableBuilder builder) {
- }
+ public void initSendable(SendableBuilder builder) {}
private int m_channelIndex = -1;
private static final Lock m_mutex = new ReentrantLock(true);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalInput.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalInput.java
index 7cbd1ed..5b4cf5e 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalInput.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalInput.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -11,8 +8,9 @@
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Class to read a digital input. This class will read digital inputs and return the current value
@@ -20,7 +18,7 @@
* elsewhere will automatically allocate digital inputs and outputs as required. This class is only
* for devices like switches etc. that aren't implemented anywhere else.
*/
-public class DigitalInput extends DigitalSource implements Sendable, AutoCloseable {
+public class DigitalInput extends DigitalSource implements Sendable {
private final int m_channel;
private int m_handle;
@@ -43,9 +41,6 @@
public void close() {
super.close();
SendableRegistry.remove(this);
- if (m_interrupt != 0) {
- cancelInterrupts();
- }
DIOJNI.freeDIOPort(m_handle);
m_handle = 0;
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java
index ec1a44c..2c87df5 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalOutput.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -11,14 +8,15 @@
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Class to write digital outputs. This class will write digital outputs. Other devices that are
* implemented elsewhere will automatically allocate digital inputs and outputs as required.
*/
-public class DigitalOutput extends DigitalSource implements Sendable, AutoCloseable {
+public class DigitalOutput extends DigitalSource implements Sendable {
private static final int invalidPwmGenerator = 0;
private int m_pwmGenerator = invalidPwmGenerator;
@@ -26,11 +24,10 @@
private int m_handle;
/**
- * Create an instance of a digital output. Create an instance of a digital output given a
- * channel.
+ * Create an instance of a digital output. Create an instance of a digital output given a channel.
*
* @param channel the DIO channel to use for the digital output. 0-9 are on-board, 10-25 are on
- * the MXP
+ * the MXP
*/
public DigitalOutput(int channel) {
SensorUtil.checkDigitalChannel(channel);
@@ -60,7 +57,7 @@
* @param value true is on, off is false
*/
public void set(boolean value) {
- DIOJNI.setDIO(m_handle, (short) (value ? 1 : 0));
+ DIOJNI.setDIO(m_handle, value);
}
/**
@@ -153,8 +150,7 @@
* Change the duty-cycle that is being generated on the line.
*
* <p>The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less) but is reduced
- * the
- * higher the frequency of the PWM signal is.
+ * the higher the frequency of the PWM signal is.
*
* @param dutyCycle The duty-cycle to change to. [0..1]
*/
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalSource.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalSource.java
index d31e191..cb8b024 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalSource.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DigitalSource.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -13,8 +10,25 @@
* just provides a channel, then a digital input will be constructed and freed when finished for the
* source. The source can either be a digital input or analog trigger but not both.
*/
-public abstract class DigitalSource extends InterruptableSensorBase {
+public abstract class DigitalSource implements AutoCloseable {
public abstract boolean isAnalogTrigger();
public abstract int getChannel();
+
+ /**
+ * If this is an analog trigger.
+ *
+ * @return true if this is an analog trigger.
+ */
+ public abstract int getAnalogTriggerTypeForRouting();
+
+ /**
+ * The channel routing number.
+ *
+ * @return channel routing number
+ */
+ public abstract int getPortHandleForRouting();
+
+ @Override
+ public void close() {}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DoubleSolenoid.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DoubleSolenoid.java
index d6d4908..68a1bca 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DoubleSolenoid.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DoubleSolenoid.java
@@ -1,94 +1,118 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.hal.SolenoidJNI;
-import edu.wpi.first.hal.util.UncleanStatusException;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.hal.util.AllocationException;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
- * DoubleSolenoid class for running 2 channels of high voltage Digital Output on the PCM.
+ * DoubleSolenoid class for running 2 channels of high voltage Digital Output on the pneumatics
+ * module.
*
* <p>The DoubleSolenoid class is typically used for pneumatics solenoids that have two positions
* controlled by two separate channels.
*/
-public class DoubleSolenoid extends SolenoidBase implements Sendable, AutoCloseable {
- /**
- * Possible values for a DoubleSolenoid.
- */
+public class DoubleSolenoid implements Sendable, AutoCloseable {
+ /** Possible values for a DoubleSolenoid. */
public enum Value {
kOff,
kForward,
kReverse
}
- private byte m_forwardMask; // The mask for the forward channel.
- private byte m_reverseMask; // The mask for the reverse channel.
- private int m_forwardHandle;
- private int m_reverseHandle;
+ private final int m_forwardMask; // The mask for the forward channel.
+ private final int m_reverseMask; // The mask for the reverse channel.
+ private final int m_mask; // The channel mask
+ private PneumaticsBase m_module;
+ private final int m_forwardChannel;
+ private final int m_reverseChannel;
/**
- * Constructor. Uses the default PCM ID (defaults to 0).
+ * Constructs a double solenoid for a default module of a specific module type.
*
- * @param forwardChannel The forward channel number on the PCM (0..7).
- * @param reverseChannel The reverse channel number on the PCM (0..7).
+ * @param moduleType The module type to use.
+ * @param forwardChannel The forward channel on the module to control.
+ * @param reverseChannel The reverse channel on the module to control.
*/
- public DoubleSolenoid(final int forwardChannel, final int reverseChannel) {
- this(SensorUtil.getDefaultSolenoidModule(), forwardChannel, reverseChannel);
+ public DoubleSolenoid(
+ final PneumaticsModuleType moduleType, final int forwardChannel, final int reverseChannel) {
+ this(PneumaticsBase.getDefaultForType(moduleType), moduleType, forwardChannel, reverseChannel);
}
/**
- * Constructor.
+ * Constructs a double solenoid for a specified module of a specific module type.
*
- * @param moduleNumber The module number of the solenoid module to use.
- * @param forwardChannel The forward channel on the module to control (0..7).
- * @param reverseChannel The reverse channel on the module to control (0..7).
+ * @param module The module of the solenoid module to use.
+ * @param moduleType The module type to use.
+ * @param forwardChannel The forward channel on the module to control.
+ * @param reverseChannel The reverse channel on the module to control.
*/
- public DoubleSolenoid(final int moduleNumber, final int forwardChannel,
- final int reverseChannel) {
- super(moduleNumber);
+ public DoubleSolenoid(
+ final int module,
+ final PneumaticsModuleType moduleType,
+ final int forwardChannel,
+ final int reverseChannel) {
+ m_module = PneumaticsBase.getForType(module, moduleType);
+ boolean allocatedSolenoids = false;
+ boolean successfulCompletion = false;
- SensorUtil.checkSolenoidModule(m_moduleNumber);
- SensorUtil.checkSolenoidChannel(forwardChannel);
- SensorUtil.checkSolenoidChannel(reverseChannel);
+ m_forwardChannel = forwardChannel;
+ m_reverseChannel = reverseChannel;
- int portHandle = HAL.getPortWithModule((byte) m_moduleNumber, (byte) forwardChannel);
- m_forwardHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
+ m_forwardMask = 1 << forwardChannel;
+ m_reverseMask = 1 << reverseChannel;
+ m_mask = m_forwardMask | m_reverseMask;
try {
- portHandle = HAL.getPortWithModule((byte) m_moduleNumber, (byte) reverseChannel);
- m_reverseHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
- } catch (UncleanStatusException ex) {
- // free the forward handle on exception, then rethrow
- SolenoidJNI.freeSolenoidPort(m_forwardHandle);
- m_forwardHandle = 0;
- m_reverseHandle = 0;
- throw ex;
+ if (!m_module.checkSolenoidChannel(forwardChannel)) {
+ throw new IllegalArgumentException("Channel " + forwardChannel + " out of range");
+ }
+
+ if (!m_module.checkSolenoidChannel(reverseChannel)) {
+ throw new IllegalArgumentException("Channel " + reverseChannel + " out of range");
+ }
+
+ int allocMask = m_module.checkAndReserveSolenoids(m_mask);
+ if (allocMask != 0) {
+ if (allocMask == m_mask) {
+ throw new AllocationException(
+ "Channels " + forwardChannel + " and " + reverseChannel + " already allocated");
+ } else if (allocMask == m_forwardMask) {
+ throw new AllocationException("Channel " + forwardChannel + " already allocated");
+ } else {
+ throw new AllocationException("Channel " + reverseChannel + " already allocated");
+ }
+ }
+ allocatedSolenoids = true;
+
+ HAL.report(
+ tResourceType.kResourceType_Solenoid, forwardChannel + 1, m_module.getModuleNumber() + 1);
+ HAL.report(
+ tResourceType.kResourceType_Solenoid, reverseChannel + 1, m_module.getModuleNumber() + 1);
+ SendableRegistry.addLW(this, "DoubleSolenoid", m_module.getModuleNumber(), forwardChannel);
+ successfulCompletion = true;
+ } finally {
+ if (!successfulCompletion) {
+ if (allocatedSolenoids) {
+ m_module.unreserveSolenoids(m_mask);
+ }
+ m_module.close();
+ }
}
-
- m_forwardMask = (byte) (1 << forwardChannel);
- m_reverseMask = (byte) (1 << reverseChannel);
-
- HAL.report(tResourceType.kResourceType_Solenoid, forwardChannel + 1,
- m_moduleNumber + 1);
- HAL.report(tResourceType.kResourceType_Solenoid, reverseChannel + 1,
- m_moduleNumber + 1);
- SendableRegistry.addLW(this, "DoubleSolenoid", m_moduleNumber, forwardChannel);
}
@Override
public synchronized void close() {
SendableRegistry.remove(this);
- SolenoidJNI.freeSolenoidPort(m_forwardHandle);
- SolenoidJNI.freeSolenoidPort(m_reverseHandle);
+ m_module.unreserveSolenoids(m_mask);
+ m_module.close();
+ m_module = null;
}
/**
@@ -97,29 +121,23 @@
* @param value The value to set (Off, Forward, Reverse)
*/
public void set(final Value value) {
- boolean forward = false;
- boolean reverse = false;
+ int setValue;
switch (value) {
case kOff:
- forward = false;
- reverse = false;
+ setValue = 0;
break;
case kForward:
- forward = true;
- reverse = false;
+ setValue = m_forwardMask;
break;
case kReverse:
- forward = false;
- reverse = true;
+ setValue = m_reverseMask;
break;
default:
throw new AssertionError("Illegal value: " + value);
-
}
- SolenoidJNI.setSolenoid(m_forwardHandle, forward);
- SolenoidJNI.setSolenoid(m_reverseHandle, reverse);
+ m_module.setSolenoids(m_mask, setValue);
}
/**
@@ -128,12 +146,11 @@
* @return The current value of the solenoid.
*/
public Value get() {
- boolean valueForward = SolenoidJNI.getSolenoid(m_forwardHandle);
- boolean valueReverse = SolenoidJNI.getSolenoid(m_reverseHandle);
+ int values = m_module.getSolenoids();
- if (valueForward) {
+ if ((values & m_forwardMask) != 0) {
return Value.kForward;
- } else if (valueReverse) {
+ } else if ((values & m_reverseMask) != 0) {
return Value.kReverse;
} else {
return Value.kOff;
@@ -157,27 +174,41 @@
}
/**
- * Check if the forward solenoid is blacklisted. If a solenoid is shorted, it is added to the
- * blacklist and disabled until power cycle, or until faults are cleared.
+ * Get the forward channel.
*
- * @return If solenoid is disabled due to short.
- * @see #clearAllPCMStickyFaults()
+ * @return the forward channel.
*/
- public boolean isFwdSolenoidBlackListed() {
- int blackList = getPCMSolenoidBlackList();
- return (blackList & m_forwardMask) != 0;
+ public int getFwdChannel() {
+ return m_forwardChannel;
}
/**
- * Check if the reverse solenoid is blacklisted. If a solenoid is shorted, it is added to the
- * blacklist and disabled until power cycle, or until faults are cleared.
+ * Get the reverse channel.
+ *
+ * @return the reverse channel.
+ */
+ public int getRevChannel() {
+ return m_reverseChannel;
+ }
+
+ /**
+ * Check if the forward solenoid is Disabled. If a solenoid is shorted, it is added to the
+ * DisabledList and disabled until power cycle, or until faults are cleared.
*
* @return If solenoid is disabled due to short.
- * @see #clearAllPCMStickyFaults()
*/
- public boolean isRevSolenoidBlackListed() {
- int blackList = getPCMSolenoidBlackList();
- return (blackList & m_reverseMask) != 0;
+ public boolean isFwdSolenoidDisabled() {
+ return (m_module.getSolenoidDisabledList() & m_forwardMask) != 0;
+ }
+
+ /**
+ * Check if the reverse solenoid is Disabled. If a solenoid is shorted, it is added to the
+ * DisabledList and disabled until power cycle, or until faults are cleared.
+ *
+ * @return If solenoid is disabled due to short.
+ */
+ public boolean isRevSolenoidDisabled() {
+ return (m_module.getSolenoidDisabledList() & m_reverseMask) != 0;
}
@Override
@@ -185,14 +216,17 @@
builder.setSmartDashboardType("Double Solenoid");
builder.setActuator(true);
builder.setSafeState(() -> set(Value.kOff));
- builder.addStringProperty("Value", () -> get().name().substring(1), value -> {
- if ("Forward".equals(value)) {
- set(Value.kForward);
- } else if ("Reverse".equals(value)) {
- set(Value.kReverse);
- } else {
- set(Value.kOff);
- }
- });
+ builder.addStringProperty(
+ "Value",
+ () -> get().name().substring(1),
+ value -> {
+ if ("Forward".equals(value)) {
+ set(Value.kForward);
+ } else if ("Reverse".equals(value)) {
+ set(Value.kReverse);
+ } else {
+ set(Value.kOff);
+ }
+ });
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DriverStation.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DriverStation.java
index fe3ca50..c450c5e 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DriverStation.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DriverStation.java
@@ -1,18 +1,9 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.ByteBuffer;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
import edu.wpi.first.hal.AllianceStationID;
import edu.wpi.first.hal.ControlWord;
import edu.wpi.first.hal.HAL;
@@ -20,16 +11,15 @@
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
-/**
- * Provide access to the network communication data to / from the Driver Station.
- */
-@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ExcessiveClassLength",
- "PMD.ExcessivePublicCount", "PMD.GodClass", "PMD.TooManyFields"})
+/** Provide access to the network communication data to / from the Driver Station. */
public class DriverStation {
- /**
- * Number of Joystick Ports.
- */
+ /** Number of Joystick Ports. */
public static final int kJoystickPorts = 6;
private static class HALJoystickButtons {
@@ -58,55 +48,87 @@
}
}
- /**
- * The robot alliance that the robot is a part of.
- */
+ /** The robot alliance that the robot is a part of. */
public enum Alliance {
- Red, Blue, Invalid
+ Red,
+ Blue,
+ Invalid
}
public enum MatchType {
- None, Practice, Qualification, Elimination
+ None,
+ Practice,
+ Qualification,
+ Elimination
}
private static final double JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL = 1.0;
- private double m_nextMessageTime;
+ private static double m_nextMessageTime;
private static class DriverStationTask implements Runnable {
- private final DriverStation m_ds;
-
- DriverStationTask(DriverStation ds) {
- m_ds = ds;
- }
+ DriverStationTask() {}
@Override
public void run() {
- m_ds.run();
+ DriverStation.run();
}
} /* DriverStationTask */
private static class MatchDataSender {
@SuppressWarnings("MemberName")
NetworkTable table;
+
@SuppressWarnings("MemberName")
NetworkTableEntry typeMetadata;
+
@SuppressWarnings("MemberName")
NetworkTableEntry gameSpecificMessage;
+
@SuppressWarnings("MemberName")
NetworkTableEntry eventName;
+
@SuppressWarnings("MemberName")
NetworkTableEntry matchNumber;
+
@SuppressWarnings("MemberName")
NetworkTableEntry replayNumber;
+
@SuppressWarnings("MemberName")
NetworkTableEntry matchType;
+
@SuppressWarnings("MemberName")
NetworkTableEntry alliance;
+
@SuppressWarnings("MemberName")
NetworkTableEntry station;
+
@SuppressWarnings("MemberName")
NetworkTableEntry controlWord;
+ @SuppressWarnings("MemberName")
+ boolean oldIsRedAlliance = true;
+
+ @SuppressWarnings("MemberName")
+ int oldStationNumber = 1;
+
+ @SuppressWarnings("MemberName")
+ String oldEventName = "";
+
+ @SuppressWarnings("MemberName")
+ String oldGameSpecificMessage = "";
+
+ @SuppressWarnings("MemberName")
+ int oldMatchNumber;
+
+ @SuppressWarnings("MemberName")
+ int oldReplayNumber;
+
+ @SuppressWarnings("MemberName")
+ int oldMatchType;
+
+ @SuppressWarnings("MemberName")
+ int oldControlWord;
+
MatchDataSender() {
table = NetworkTableInstance.getDefault().getTable("FMSInfo");
typeMetadata = table.getEntry(".type");
@@ -128,61 +150,147 @@
controlWord = table.getEntry("FMSControlData");
controlWord.forceSetDouble(0);
}
+
+ private void sendMatchData() {
+ AllianceStationID allianceID = HAL.getAllianceStation();
+ boolean isRedAlliance = false;
+ int stationNumber = 1;
+ switch (allianceID) {
+ case Blue1:
+ isRedAlliance = false;
+ stationNumber = 1;
+ break;
+ case Blue2:
+ isRedAlliance = false;
+ stationNumber = 2;
+ break;
+ case Blue3:
+ isRedAlliance = false;
+ stationNumber = 3;
+ break;
+ case Red1:
+ isRedAlliance = true;
+ stationNumber = 1;
+ break;
+ case Red2:
+ isRedAlliance = true;
+ stationNumber = 2;
+ break;
+ default:
+ isRedAlliance = true;
+ stationNumber = 3;
+ break;
+ }
+
+ String currentEventName;
+ String currentGameSpecificMessage;
+ int currentMatchNumber;
+ int currentReplayNumber;
+ int currentMatchType;
+ int currentControlWord;
+ m_cacheDataMutex.lock();
+ try {
+ currentEventName = DriverStation.m_matchInfo.eventName;
+ currentGameSpecificMessage = DriverStation.m_matchInfo.gameSpecificMessage;
+ currentMatchNumber = DriverStation.m_matchInfo.matchNumber;
+ currentReplayNumber = DriverStation.m_matchInfo.replayNumber;
+ currentMatchType = DriverStation.m_matchInfo.matchType;
+ } finally {
+ m_cacheDataMutex.unlock();
+ }
+ currentControlWord = HAL.nativeGetControlWord();
+
+ if (oldIsRedAlliance != isRedAlliance) {
+ alliance.setBoolean(isRedAlliance);
+ oldIsRedAlliance = isRedAlliance;
+ }
+ if (oldStationNumber != stationNumber) {
+ station.setDouble(stationNumber);
+ oldStationNumber = stationNumber;
+ }
+ if (!oldEventName.equals(currentEventName)) {
+ eventName.setString(currentEventName);
+ oldEventName = currentEventName;
+ }
+ if (!oldGameSpecificMessage.equals(currentGameSpecificMessage)) {
+ gameSpecificMessage.setString(currentGameSpecificMessage);
+ oldGameSpecificMessage = currentGameSpecificMessage;
+ }
+ if (currentMatchNumber != oldMatchNumber) {
+ matchNumber.setDouble(currentMatchNumber);
+ oldMatchNumber = currentMatchNumber;
+ }
+ if (currentReplayNumber != oldReplayNumber) {
+ replayNumber.setDouble(currentReplayNumber);
+ oldReplayNumber = currentReplayNumber;
+ }
+ if (currentMatchType != oldMatchType) {
+ matchType.setDouble(currentMatchType);
+ oldMatchType = currentMatchType;
+ }
+ if (currentControlWord != oldControlWord) {
+ controlWord.setDouble(currentControlWord);
+ oldControlWord = currentControlWord;
+ }
+ }
}
private static DriverStation instance = new DriverStation();
// Joystick User Data
- private HALJoystickAxes[] m_joystickAxes = new HALJoystickAxes[kJoystickPorts];
- private HALJoystickPOVs[] m_joystickPOVs = new HALJoystickPOVs[kJoystickPorts];
- private HALJoystickButtons[] m_joystickButtons = new HALJoystickButtons[kJoystickPorts];
- private MatchInfoData m_matchInfo = new MatchInfoData();
+ private static HALJoystickAxes[] m_joystickAxes = new HALJoystickAxes[kJoystickPorts];
+ private static HALJoystickPOVs[] m_joystickPOVs = new HALJoystickPOVs[kJoystickPorts];
+ private static HALJoystickButtons[] m_joystickButtons = new HALJoystickButtons[kJoystickPorts];
+ private static MatchInfoData m_matchInfo = new MatchInfoData();
// Joystick Cached Data
- private HALJoystickAxes[] m_joystickAxesCache = new HALJoystickAxes[kJoystickPorts];
- private HALJoystickPOVs[] m_joystickPOVsCache = new HALJoystickPOVs[kJoystickPorts];
- private HALJoystickButtons[] m_joystickButtonsCache = new HALJoystickButtons[kJoystickPorts];
- private MatchInfoData m_matchInfoCache = new MatchInfoData();
+ private static HALJoystickAxes[] m_joystickAxesCache = new HALJoystickAxes[kJoystickPorts];
+ private static HALJoystickPOVs[] m_joystickPOVsCache = new HALJoystickPOVs[kJoystickPorts];
+ private static HALJoystickButtons[] m_joystickButtonsCache =
+ new HALJoystickButtons[kJoystickPorts];
+ private static MatchInfoData m_matchInfoCache = new MatchInfoData();
// Joystick button rising/falling edge flags
- private int[] m_joystickButtonsPressed = new int[kJoystickPorts];
- private int[] m_joystickButtonsReleased = new int[kJoystickPorts];
+ private static int[] m_joystickButtonsPressed = new int[kJoystickPorts];
+ private static int[] m_joystickButtonsReleased = new int[kJoystickPorts];
// preallocated byte buffer for button count
- private final ByteBuffer m_buttonCountBuffer = ByteBuffer.allocateDirect(1);
+ private static final ByteBuffer m_buttonCountBuffer = ByteBuffer.allocateDirect(1);
- private final MatchDataSender m_matchDataSender;
+ private static final MatchDataSender m_matchDataSender;
// Internal Driver Station thread
- @SuppressWarnings("PMD.SingularField")
- private final Thread m_thread;
- private volatile boolean m_threadKeepAlive = true;
+ private static Thread m_thread;
- private final ReentrantLock m_cacheDataMutex = new ReentrantLock();
+ private static volatile boolean m_threadKeepAlive = true;
- private final Lock m_waitForDataMutex;
- private final Condition m_waitForDataCond;
- private int m_waitForDataCount;
- private final ThreadLocal<Integer> m_lastCount = ThreadLocal.withInitial(() -> 0);
+ private static final ReentrantLock m_cacheDataMutex = new ReentrantLock();
- private boolean m_silenceJoystickWarning;
+ private static final Lock m_waitForDataMutex;
+ private static final Condition m_waitForDataCond;
+ private static int m_waitForDataCount;
+ private static final ThreadLocal<Integer> m_lastCount = ThreadLocal.withInitial(() -> 0);
+
+ private static boolean m_silenceJoystickWarning;
// Robot state status variables
- private boolean m_userInDisabled;
- private boolean m_userInAutonomous;
- private boolean m_userInTeleop;
- private boolean m_userInTest;
+ private static boolean m_userInDisabled;
+ private static boolean m_userInAutonomous;
+ private static boolean m_userInTeleop;
+ private static boolean m_userInTest;
// Control word variables
- private final Object m_controlWordMutex;
- private final ControlWord m_controlWordCache;
- private long m_lastControlWordUpdate;
+ private static final Object m_controlWordMutex;
+ private static final ControlWord m_controlWordCache;
+ private static long m_lastControlWordUpdate;
/**
* Gets an instance of the DriverStation.
*
* @return The DriverStation.
+ * @deprecated Use the static methods
*/
+ @Deprecated
public static DriverStation getInstance() {
return DriverStation.instance;
}
@@ -193,8 +301,9 @@
* <p>The single DriverStation instance is created statically with the instance static member
* variable.
*/
- @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
- private DriverStation() {
+ private DriverStation() {}
+
+ static {
HAL.initialize(500, 0);
m_waitForDataCount = 0;
m_waitForDataMutex = new ReentrantLock();
@@ -216,23 +325,29 @@
m_matchDataSender = new MatchDataSender();
- m_thread = new Thread(new DriverStationTask(this), "FRCDriverStation");
+ m_thread = new Thread(new DriverStationTask(), "FRCDriverStation");
m_thread.setPriority((Thread.NORM_PRIORITY + Thread.MAX_PRIORITY) / 2);
m_thread.start();
}
- /**
- * Kill the thread.
- */
- public void release() {
+ /** Kill the thread. */
+ public static synchronized void release() {
m_threadKeepAlive = false;
+ if (m_thread != null) {
+ try {
+ m_thread.join();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ m_thread = null;
+ }
}
/**
- * Report error to Driver Station. Optionally appends Stack trace
- * to error message.
+ * Report error to Driver Station. Optionally appends Stack trace to error message.
*
+ * @param error The error to report.
* @param printTrace If true, append stack trace to error string
*/
public static void reportError(String error, boolean printTrace) {
@@ -240,9 +355,9 @@
}
/**
- * Report error to Driver Station. Appends provided stack trace
- * to error message.
+ * Report error to Driver Station. Appends provided stack trace to error message.
*
+ * @param error The error to report.
* @param stackTrace The stack trace to append
*/
public static void reportError(String error, StackTraceElement[] stackTrace) {
@@ -250,37 +365,41 @@
}
/**
- * Report warning to Driver Station. Optionally appends Stack
- * trace to warning message.
+ * Report warning to Driver Station. Optionally appends Stack trace to warning message.
*
+ * @param warning The warning to report.
* @param printTrace If true, append stack trace to warning string
*/
- public static void reportWarning(String error, boolean printTrace) {
- reportErrorImpl(false, 1, error, printTrace);
+ public static void reportWarning(String warning, boolean printTrace) {
+ reportErrorImpl(false, 1, warning, printTrace);
}
/**
- * Report warning to Driver Station. Appends provided stack
- * trace to warning message.
+ * Report warning to Driver Station. Appends provided stack trace to warning message.
*
+ * @param warning The warning to report.
* @param stackTrace The stack trace to append
*/
- public static void reportWarning(String error, StackTraceElement[] stackTrace) {
- reportErrorImpl(false, 1, error, stackTrace);
+ public static void reportWarning(String warning, StackTraceElement[] stackTrace) {
+ reportErrorImpl(false, 1, warning, stackTrace);
}
- private static void reportErrorImpl(boolean isError, int code, String error, boolean
- printTrace) {
+ private static void reportErrorImpl(boolean isError, int code, String error, boolean printTrace) {
reportErrorImpl(isError, code, error, printTrace, Thread.currentThread().getStackTrace(), 3);
}
- private static void reportErrorImpl(boolean isError, int code, String error,
- StackTraceElement[] stackTrace) {
+ private static void reportErrorImpl(
+ boolean isError, int code, String error, StackTraceElement[] stackTrace) {
reportErrorImpl(isError, code, error, true, stackTrace, 0);
}
- private static void reportErrorImpl(boolean isError, int code, String error,
- boolean printTrace, StackTraceElement[] stackTrace, int stackTraceFirst) {
+ private static void reportErrorImpl(
+ boolean isError,
+ int code,
+ String error,
+ boolean printTrace,
+ StackTraceElement[] stackTrace,
+ int stackTraceFirst) {
String locString;
if (stackTrace.length >= stackTraceFirst + 1) {
locString = stackTrace[stackTraceFirst].toString();
@@ -306,11 +425,11 @@
/**
* The state of one joystick button. Button indexes begin at 1.
*
- * @param stick The joystick to read.
+ * @param stick The joystick to read.
* @param button The button index, beginning at 1.
* @return The state of the joystick button.
*/
- public boolean getStickButton(final int stick, final int button) {
+ public static boolean getStickButton(final int stick, final int button) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-3");
}
@@ -328,19 +447,23 @@
m_cacheDataMutex.unlock();
}
- reportJoystickUnpluggedWarning("Joystick Button " + button + " on port " + stick
- + " not available, check if controller is plugged in");
+ reportJoystickUnpluggedWarning(
+ "Joystick Button "
+ + button
+ + " on port "
+ + stick
+ + " not available, check if controller is plugged in");
return false;
}
/**
* Whether one joystick button was pressed since the last check. Button indexes begin at 1.
*
- * @param stick The joystick to read.
+ * @param stick The joystick to read.
* @param button The button index, beginning at 1.
* @return Whether the joystick button was pressed since the last check.
*/
- public boolean getStickButtonPressed(final int stick, final int button) {
+ public static boolean getStickButtonPressed(final int stick, final int button) {
if (button <= 0) {
reportJoystickUnpluggedError("Button indexes begin at 1 in WPILib for C++ and Java\n");
return false;
@@ -364,20 +487,23 @@
m_cacheDataMutex.unlock();
}
- reportJoystickUnpluggedWarning("Joystick Button " + button + " on port " + stick
- + " not available, check if controller is plugged in");
+ reportJoystickUnpluggedWarning(
+ "Joystick Button "
+ + button
+ + " on port "
+ + stick
+ + " not available, check if controller is plugged in");
return false;
}
/**
- * Whether one joystick button was released since the last check. Button indexes
- * begin at 1.
+ * Whether one joystick button was released since the last check. Button indexes begin at 1.
*
- * @param stick The joystick to read.
+ * @param stick The joystick to read.
* @param button The button index, beginning at 1.
* @return Whether the joystick button was released since the last check.
*/
- public boolean getStickButtonReleased(final int stick, final int button) {
+ public static boolean getStickButtonReleased(final int stick, final int button) {
if (button <= 0) {
reportJoystickUnpluggedError("Button indexes begin at 1 in WPILib for C++ and Java\n");
return false;
@@ -401,8 +527,12 @@
m_cacheDataMutex.unlock();
}
- reportJoystickUnpluggedWarning("Joystick Button " + button + " on port " + stick
- + " not available, check if controller is plugged in");
+ reportJoystickUnpluggedWarning(
+ "Joystick Button "
+ + button
+ + " on port "
+ + stick
+ + " not available, check if controller is plugged in");
return false;
}
@@ -411,10 +541,10 @@
* to the specified port.
*
* @param stick The joystick to read.
- * @param axis The analog axis value to read from the joystick.
+ * @param axis The analog axis value to read from the joystick.
* @return The value of the axis on the joystick.
*/
- public double getStickAxis(int stick, int axis) {
+ public static double getStickAxis(int stick, int axis) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -431,17 +561,23 @@
m_cacheDataMutex.unlock();
}
- reportJoystickUnpluggedWarning("Joystick axis " + axis + " on port " + stick
- + " not available, check if controller is plugged in");
+ reportJoystickUnpluggedWarning(
+ "Joystick axis "
+ + axis
+ + " on port "
+ + stick
+ + " not available, check if controller is plugged in");
return 0.0;
}
/**
* Get the state of a POV on the joystick.
*
+ * @param stick The joystick to read.
+ * @param pov The POV to read.
* @return the angle of the POV in degrees, or -1 if the POV is not pressed.
*/
- public int getStickPOV(int stick, int pov) {
+ public static int getStickPOV(int stick, int pov) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -458,8 +594,12 @@
m_cacheDataMutex.unlock();
}
- reportJoystickUnpluggedWarning("Joystick POV " + pov + " on port " + stick
- + " not available, check if controller is plugged in");
+ reportJoystickUnpluggedWarning(
+ "Joystick POV "
+ + pov
+ + " on port "
+ + stick
+ + " not available, check if controller is plugged in");
return -1;
}
@@ -469,7 +609,7 @@
* @param stick The joystick to read.
* @return The state of the buttons on the joystick.
*/
- public int getStickButtons(final int stick) {
+ public static int getStickButtons(final int stick) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-3");
}
@@ -488,7 +628,7 @@
* @param stick The joystick port number
* @return The number of axes on the indicated joystick
*/
- public int getStickAxisCount(int stick) {
+ public static int getStickAxisCount(int stick) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -507,7 +647,7 @@
* @param stick The joystick port number
* @return The number of POVs on the indicated joystick
*/
- public int getStickPOVCount(int stick) {
+ public static int getStickPOVCount(int stick) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -526,7 +666,7 @@
* @param stick The joystick port number
* @return The number of buttons on the indicated joystick
*/
- public int getStickButtonCount(int stick) {
+ public static int getStickButtonCount(int stick) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -545,7 +685,7 @@
* @param stick The joystick port number
* @return A boolean that returns the value of isXbox
*/
- public boolean getJoystickIsXbox(int stick) {
+ public static boolean getJoystickIsXbox(int stick) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -559,7 +699,7 @@
* @param stick The joystick port number
* @return The value of type
*/
- public int getJoystickType(int stick) {
+ public static int getJoystickType(int stick) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -573,7 +713,7 @@
* @param stick The joystick port number
* @return The value of name
*/
- public String getJoystickName(int stick) {
+ public static String getJoystickName(int stick) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -588,7 +728,7 @@
* @param axis The target axis
* @return What type of axis the axis is reporting to be
*/
- public int getJoystickAxisType(int stick, int axis) {
+ public static int getJoystickAxisType(int stick, int axis) {
if (stick < 0 || stick >= kJoystickPorts) {
throw new IllegalArgumentException("Joystick index is out of range, should be 0-5");
}
@@ -599,16 +739,16 @@
/**
* Returns if a joystick is connected to the Driver Station.
*
- * <p>This makes a best effort guess by looking at the reported number of axis,
- * buttons, and POVs attached.
+ * <p>This makes a best effort guess by looking at the reported number of axis, buttons, and POVs
+ * attached.
*
* @param stick The joystick port number
* @return true if a joystick is connected
*/
- public boolean isJoystickConnected(int stick) {
+ public static boolean isJoystickConnected(int stick) {
return getStickAxisCount(stick) > 0
- || getStickButtonCount(stick) > 0
- || getStickPOVCount(stick) > 0;
+ || getStickButtonCount(stick) > 0
+ || getStickPOVCount(stick) > 0;
}
/**
@@ -616,7 +756,7 @@
*
* @return True if the robot is enabled, false otherwise.
*/
- public boolean isEnabled() {
+ public static boolean isEnabled() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
return m_controlWordCache.getEnabled() && m_controlWordCache.getDSAttached();
@@ -628,7 +768,7 @@
*
* @return True if the robot should be disabled, false otherwise.
*/
- public boolean isDisabled() {
+ public static boolean isDisabled() {
return !isEnabled();
}
@@ -637,7 +777,7 @@
*
* @return True if the robot is e-stopped, false otherwise.
*/
- public boolean isEStopped() {
+ public static boolean isEStopped() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
return m_controlWordCache.getEStop();
@@ -650,7 +790,7 @@
*
* @return True if autonomous mode should be enabled, false otherwise.
*/
- public boolean isAutonomous() {
+ public static boolean isAutonomous() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
return m_controlWordCache.getAutonomous();
@@ -663,7 +803,7 @@
*
* @return True if autonomous should be set and the robot should be enabled.
*/
- public boolean isAutonomousEnabled() {
+ public static boolean isAutonomousEnabled() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
return m_controlWordCache.getAutonomous() && m_controlWordCache.getEnabled();
@@ -675,8 +815,20 @@
* operator-controlled mode.
*
* @return True if operator-controlled mode should be enabled, false otherwise.
+ * @deprecated Use isTeleop() instead.
*/
- public boolean isOperatorControl() {
+ @Deprecated(since = "2022", forRemoval = true)
+ public static boolean isOperatorControl() {
+ return isTeleop();
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be running in
+ * operator-controlled mode.
+ *
+ * @return True if operator-controlled mode should be enabled, false otherwise.
+ */
+ public static boolean isTeleop() {
return !(isAutonomous() || isTest());
}
@@ -685,11 +837,24 @@
* operator-controller mode and enabled.
*
* @return True if operator-controlled mode should be set and the robot should be enabled.
+ * @deprecated Use isTeleopEnabled() instead.
*/
- public boolean isOperatorControlEnabled() {
+ @Deprecated(since = "2022", forRemoval = true)
+ public static boolean isOperatorControlEnabled() {
+ return isTeleopEnabled();
+ }
+
+ /**
+ * Gets a value indicating whether the Driver Station requires the robot to be running in
+ * operator-controller mode and enabled.
+ *
+ * @return True if operator-controlled mode should be set and the robot should be enabled.
+ */
+ public static boolean isTeleopEnabled() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
- return !m_controlWordCache.getAutonomous() && !m_controlWordCache.getTest()
+ return !m_controlWordCache.getAutonomous()
+ && !m_controlWordCache.getTest()
&& m_controlWordCache.getEnabled();
}
}
@@ -700,7 +865,7 @@
*
* @return True if test mode should be enabled, false otherwise.
*/
- public boolean isTest() {
+ public static boolean isTest() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
return m_controlWordCache.getTest();
@@ -712,7 +877,7 @@
*
* @return True if Driver Station is attached, false otherwise.
*/
- public boolean isDSAttached() {
+ public static boolean isDSAttached() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
return m_controlWordCache.getDSAttached();
@@ -725,7 +890,7 @@
*
* @return True if the control data has been updated since the last call.
*/
- public boolean isNewControlData() {
+ public static boolean isNewControlData() {
m_waitForDataMutex.lock();
try {
int currentCount = m_waitForDataCount;
@@ -744,7 +909,7 @@
*
* @return true if the robot is competing on a field being controlled by a Field Management System
*/
- public boolean isFMSAttached() {
+ public static boolean isFMSAttached() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
return m_controlWordCache.getFMSAttached();
@@ -756,7 +921,7 @@
*
* @return the game specific message
*/
- public String getGameSpecificMessage() {
+ public static String getGameSpecificMessage() {
m_cacheDataMutex.lock();
try {
return m_matchInfo.gameSpecificMessage;
@@ -770,7 +935,7 @@
*
* @return the event name
*/
- public String getEventName() {
+ public static String getEventName() {
m_cacheDataMutex.lock();
try {
return m_matchInfo.eventName;
@@ -784,7 +949,7 @@
*
* @return the match type
*/
- public MatchType getMatchType() {
+ public static MatchType getMatchType() {
int matchType;
m_cacheDataMutex.lock();
try {
@@ -809,7 +974,7 @@
*
* @return the match number
*/
- public int getMatchNumber() {
+ public static int getMatchNumber() {
m_cacheDataMutex.lock();
try {
return m_matchInfo.matchNumber;
@@ -823,7 +988,7 @@
*
* @return the replay number
*/
- public int getReplayNumber() {
+ public static int getReplayNumber() {
m_cacheDataMutex.lock();
try {
return m_matchInfo.replayNumber;
@@ -837,7 +1002,7 @@
*
* @return the current alliance
*/
- public Alliance getAlliance() {
+ public static Alliance getAlliance() {
AllianceStationID allianceStationID = HAL.getAllianceStation();
if (allianceStationID == null) {
return Alliance.Invalid;
@@ -864,7 +1029,7 @@
*
* @return the location of the team's driver station controls: 1, 2, or 3
*/
- public int getLocation() {
+ public static int getLocation() {
AllianceStationID allianceStationID = HAL.getAllianceStation();
if (allianceStationID == null) {
return 0;
@@ -890,10 +1055,10 @@
/**
* Wait for new data from the driver station.
*
- * <p>Checks if new control data has arrived since the last waitForData call
- * on the current thread. If new data has not arrived, returns immediately.
+ * <p>Checks if new control data has arrived since the last waitForData call on the current
+ * thread. If new data has not arrived, returns immediately.
*/
- public void waitForData() {
+ public static void waitForData() {
waitForData(0);
}
@@ -901,15 +1066,15 @@
* Wait for new data or for timeout, which ever comes first. If timeout is 0, wait for new data
* only.
*
- * <p>Checks if new control data has arrived since the last waitForData call
- * on the current thread. If new data has not arrived, returns immediately.
+ * <p>Checks if new control data has arrived since the last waitForData call on the current
+ * thread. If new data has not arrived, returns immediately.
*
- * @param timeout The maximum time in seconds to wait.
+ * @param timeoutSeconds The maximum time in seconds to wait.
* @return true if there is new data, otherwise false
*/
- public boolean waitForData(double timeout) {
- long startTime = RobotController.getFPGATime();
- long timeoutMicros = (long) (timeout * 1000000);
+ public static boolean waitForData(double timeoutSeconds) {
+ long startTimeMicroS = RobotController.getFPGATime();
+ long timeoutMicroS = (long) (timeoutSeconds * 1e6);
m_waitForDataMutex.lock();
try {
int currentCount = m_waitForDataCount;
@@ -918,12 +1083,13 @@
return true;
}
while (m_waitForDataCount == currentCount) {
- if (timeout > 0) {
- long now = RobotController.getFPGATime();
- if (now < startTime + timeoutMicros) {
+ if (timeoutMicroS > 0) {
+ long nowMicroS = RobotController.getFPGATime();
+ if (nowMicroS < startTimeMicroS + timeoutMicroS) {
// We still have time to wait
- boolean signaled = m_waitForDataCond.await(startTime + timeoutMicros - now,
- TimeUnit.MICROSECONDS);
+ boolean signaled =
+ m_waitForDataCond.await(
+ startTimeMicroS + timeoutMicroS - nowMicroS, TimeUnit.MICROSECONDS);
if (!signaled) {
// Return false if a timeout happened
return false;
@@ -951,12 +1117,12 @@
* Return the approximate match time. The FMS does not send an official match time to the robots,
* but does send an approximate match time. The value will count down the time remaining in the
* current period (auto or teleop). Warning: This is not an official time (so it cannot be used to
- * dispute ref calls or guarantee that a function will trigger before the match ends) The
- * Practice Match function of the DS approximates the behavior seen on the field.
+ * dispute ref calls or guarantee that a function will trigger before the match ends) The Practice
+ * Match function of the DS approximates the behavior seen on the field.
*
* @return Time remaining in current match period (auto or teleop) in seconds
*/
- public double getMatchTime() {
+ public static double getMatchTime() {
return HAL.getMatchTime();
}
@@ -966,8 +1132,7 @@
*
* @param entering If true, starting disabled code; if false, leaving disabled code
*/
- @SuppressWarnings("MethodName")
- public void InDisabled(boolean entering) {
+ public static void inDisabled(boolean entering) {
m_userInDisabled = entering;
}
@@ -977,8 +1142,7 @@
*
* @param entering If true, starting autonomous code; if false, leaving autonomous code
*/
- @SuppressWarnings("MethodName")
- public void InAutonomous(boolean entering) {
+ public static void inAutonomous(boolean entering) {
m_userInAutonomous = entering;
}
@@ -987,9 +1151,20 @@
* purposes only.
*
* @param entering If true, starting teleop code; if false, leaving teleop code
+ * @deprecated Use {@link #inTeleop(boolean)} instead.
*/
- @SuppressWarnings("MethodName")
- public void InOperatorControl(boolean entering) {
+ @Deprecated(since = "2022", forRemoval = true)
+ public static void inOperatorControl(boolean entering) {
+ m_userInTeleop = entering;
+ }
+
+ /**
+ * Only to be used to tell the Driver Station what code you claim to be executing for diagnostic
+ * purposes only.
+ *
+ * @param entering If true, starting teleop code; if false, leaving teleop code
+ */
+ public static void inTeleop(boolean entering) {
m_userInTeleop = entering;
}
@@ -999,94 +1174,39 @@
*
* @param entering If true, starting test code; if false, leaving test code
*/
- @SuppressWarnings("MethodName")
- public void InTest(boolean entering) {
+ public static void inTest(boolean entering) {
m_userInTest = entering;
}
- private void sendMatchData() {
- AllianceStationID alliance = HAL.getAllianceStation();
- boolean isRedAlliance = false;
- int stationNumber = 1;
- switch (alliance) {
- case Blue1:
- isRedAlliance = false;
- stationNumber = 1;
- break;
- case Blue2:
- isRedAlliance = false;
- stationNumber = 2;
- break;
- case Blue3:
- isRedAlliance = false;
- stationNumber = 3;
- break;
- case Red1:
- isRedAlliance = true;
- stationNumber = 1;
- break;
- case Red2:
- isRedAlliance = true;
- stationNumber = 2;
- break;
- default:
- isRedAlliance = true;
- stationNumber = 3;
- break;
- }
-
-
- String eventName;
- String gameSpecificMessage;
- int matchNumber;
- int replayNumber;
- int matchType;
- synchronized (m_cacheDataMutex) {
- eventName = m_matchInfo.eventName;
- gameSpecificMessage = m_matchInfo.gameSpecificMessage;
- matchNumber = m_matchInfo.matchNumber;
- replayNumber = m_matchInfo.replayNumber;
- matchType = m_matchInfo.matchType;
- }
-
- m_matchDataSender.alliance.setBoolean(isRedAlliance);
- m_matchDataSender.station.setDouble(stationNumber);
- m_matchDataSender.eventName.setString(eventName);
- m_matchDataSender.gameSpecificMessage.setString(gameSpecificMessage);
- m_matchDataSender.matchNumber.setDouble(matchNumber);
- m_matchDataSender.replayNumber.setDouble(replayNumber);
- m_matchDataSender.matchType.setDouble(matchType);
- m_matchDataSender.controlWord.setDouble(HAL.nativeGetControlWord());
- }
-
- /**
- * Forces waitForData() to return immediately.
- */
- public void wakeupWaitForData() {
+ /** Forces waitForData() to return immediately. */
+ public static void wakeupWaitForData() {
m_waitForDataMutex.lock();
- m_waitForDataCount++;
- m_waitForDataCond.signalAll();
- m_waitForDataMutex.unlock();
+ try {
+ m_waitForDataCount++;
+ m_waitForDataCond.signalAll();
+ } finally {
+ m_waitForDataMutex.unlock();
+ }
}
/**
- * Allows the user to specify whether they want joystick connection warnings
- * to be printed to the console. This setting is ignored when the FMS is
- * connected -- warnings will always be on in that scenario.
+ * Allows the user to specify whether they want joystick connection warnings to be printed to the
+ * console. This setting is ignored when the FMS is connected -- warnings will always be on in
+ * that scenario.
*
* @param silence Whether warning messages should be silenced.
*/
- public void silenceJoystickConnectionWarning(boolean silence) {
+ public static void silenceJoystickConnectionWarning(boolean silence) {
m_silenceJoystickWarning = silence;
}
/**
- * Returns whether joystick connection warnings are silenced. This will
- * always return false when connected to the FMS.
+ * Returns whether joystick connection warnings are silenced. This will always return false when
+ * connected to the FMS.
*
* @return Whether joystick connection warnings are silenced.
*/
- public boolean isJoystickConnectionWarningSilenced() {
+ public static boolean isJoystickConnectionWarningSilenced() {
return !isFMSAttached() && m_silenceJoystickWarning;
}
@@ -1094,7 +1214,7 @@
* Copy data from the DS task for the user. If no new data exists, it will just be returned,
* otherwise the data will be copied from the DS polling loop.
*/
- protected void getData() {
+ protected static void getData() {
// Get the status of all of the joysticks
for (byte stick = 0; stick < kJoystickPorts; stick++) {
m_joystickAxesCache[stick].m_count =
@@ -1144,14 +1264,14 @@
}
wakeupWaitForData();
- sendMatchData();
+ m_matchDataSender.sendMatchData();
}
/**
* Reports errors related to unplugged joysticks Throttles the errors so that they don't overwhelm
* the DS.
*/
- private void reportJoystickUnpluggedError(String message) {
+ private static void reportJoystickUnpluggedError(String message) {
double currentTime = Timer.getFPGATimestamp();
if (currentTime > m_nextMessageTime) {
reportError(message, false);
@@ -1163,7 +1283,7 @@
* Reports errors related to unplugged joysticks Throttles the errors so that they don't overwhelm
* the DS.
*/
- private void reportJoystickUnpluggedWarning(String message) {
+ private static void reportJoystickUnpluggedWarning(String message) {
if (isFMSAttached() || !m_silenceJoystickWarning) {
double currentTime = Timer.getFPGATimestamp();
if (currentTime > m_nextMessageTime) {
@@ -1173,10 +1293,8 @@
}
}
- /**
- * Provides the service routine for the DS polling m_thread.
- */
- private void run() {
+ /** Provides the service routine for the DS polling m_thread. */
+ private static void run() {
int safetyCounter = 0;
while (m_threadKeepAlive) {
HAL.waitForDSData();
@@ -1207,12 +1325,12 @@
}
/**
- * Updates the data in the control word cache. Updates if the force parameter is set, or if
- * 50ms have passed since the last update.
+ * Updates the data in the control word cache. Updates if the force parameter is set, or if 50ms
+ * have passed since the last update.
*
* @param force True to force an update to the cache, otherwise update if 50ms have passed.
*/
- private void updateControlWord(boolean force) {
+ private static void updateControlWord(boolean force) {
long now = System.currentTimeMillis();
synchronized (m_controlWordMutex) {
if (now - m_lastControlWordUpdate > 50 || force) {
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycle.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycle.java
index 0834fad..3332f49 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycle.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycle.java
@@ -1,28 +1,24 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.DutyCycleJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Class to read a duty cycle PWM input.
*
- * <p>PWM input signals are specified with a frequency and a ratio of high to low
- * in that frequency. There are 8 of these in the roboRIO, and they can be
- * attached to any {@link DigitalSource}.
+ * <p>PWM input signals are specified with a frequency and a ratio of high to low in that frequency.
+ * There are 8 of these in the roboRIO, and they can be attached to any {@link DigitalSource}.
*
- * <p>These can be combined as the input of an AnalogTrigger to a Counter in order
- * to implement rollover checking.
- *
+ * <p>These can be combined as the input of an AnalogTrigger to a Counter in order to implement
+ * rollover checking.
*/
public class DutyCycle implements Sendable, AutoCloseable {
// Explicitly package private
@@ -38,8 +34,10 @@
* @param digitalSource The DigitalSource to use.
*/
public DutyCycle(DigitalSource digitalSource) {
- m_handle = DutyCycleJNI.initialize(digitalSource.getPortHandleForRouting(),
- digitalSource.getAnalogTriggerTypeForRouting());
+ m_handle =
+ DutyCycleJNI.initialize(
+ digitalSource.getPortHandleForRouting(),
+ digitalSource.getAnalogTriggerTypeForRouting());
m_source = digitalSource;
int index = getFPGAIndex();
@@ -47,9 +45,7 @@
SendableRegistry.addLW(this, "Duty Cycle", index);
}
- /**
- * Close the DutyCycle and free all resources.
- */
+ /** Close the DutyCycle and free all resources. */
@Override
public void close() {
DutyCycleJNI.free(m_handle);
@@ -78,8 +74,7 @@
/**
* Get the raw output ratio of the duty cycle signal.
*
- * <p>0 means always low, an output equal to getOutputScaleFactor() means always
- * high.
+ * <p>0 means always low, an output equal to getOutputScaleFactor() means always high.
*
* @return output ratio in raw units
*/
@@ -90,9 +85,8 @@
/**
* Get the scale factor of the output.
*
- * <p>An output equal to this value is always high, and then linearly scales down
- * to 0. Divide the result of getOutputRaw by this in order to get the
- * percentage between 0 and 1.
+ * <p>An output equal to this value is always high, and then linearly scales down to 0. Divide the
+ * result of getOutputRaw by this in order to get the percentage between 0 and 1.
*
* @return the output scale factor
*/
@@ -119,6 +113,5 @@
builder.setSmartDashboardType("Duty Cycle");
builder.addDoubleProperty("Frequency", this::getFrequency, null);
builder.addDoubleProperty("Output", this::getOutput, null);
-
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycleEncoder.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycleEncoder.java
index f5bba5e..ce5b684 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycleEncoder.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DutyCycleEncoder.java
@@ -1,23 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.SimBoolean;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.SimDouble;
+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.AnalogTriggerOutput.AnalogTriggerType;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
/**
- * Class for supporting duty cycle/PWM encoders, such as the US Digital MA3 with
- * PWM Output, the CTRE Mag Encoder, the Rev Hex Encoder, and the AM Mag
- * Encoder.
+ * Class for supporting duty cycle/PWM encoders, such as the US Digital MA3 with PWM Output, the
+ * CTRE Mag Encoder, the Rev Hex Encoder, and the AM Mag Encoder.
*/
public class DutyCycleEncoder implements Sendable, AutoCloseable {
private final DutyCycle m_dutyCycle;
@@ -69,12 +66,13 @@
}
private void init() {
- m_simDevice = SimDevice.create("DutyCycleEncoder", m_dutyCycle.getFPGAIndex());
+ m_simDevice = SimDevice.create("DutyCycle:DutyCycleEncoder", m_dutyCycle.getSourceChannel());
if (m_simDevice != null) {
- m_simPosition = m_simDevice.createDouble("Position", false, 0.0);
- m_simDistancePerRotation = m_simDevice.createDouble("DistancePerRotation", false, 1.0);
- m_simIsConnected = m_simDevice.createBoolean("Connected", false, true);
+ m_simPosition = m_simDevice.createDouble("position", SimDevice.Direction.kInput, 0.0);
+ m_simDistancePerRotation =
+ m_simDevice.createDouble("distance_per_rot", SimDevice.Direction.kOutput, 1.0);
+ m_simIsConnected = m_simDevice.createBoolean("connected", SimDevice.Direction.kInput, true);
} else {
m_counter = new Counter();
m_analogTrigger = new AnalogTrigger(m_dutyCycle);
@@ -121,9 +119,9 @@
/**
* Get the offset of position relative to the last reset.
*
- * <p>getPositionInRotation() - getPositionOffset() will give an encoder absolute
- * position relative to the last reset. This could potentially be negative,
- * which needs to be accounted for.
+ * <p>getPositionInRotation() - getPositionOffset() will give an encoder absolute position
+ * relative to the last reset. This could potentially be negative, which needs to be accounted
+ * for.
*
* @return the position offset
*/
@@ -132,35 +130,29 @@
}
/**
- * Set the distance per rotation of the encoder. This sets the multiplier used
- * to determine the distance driven based on the rotation value from the
- * encoder. Set this value based on the how far the mechanism travels in 1
- * rotation of the encoder, and factor in gearing reductions following the
- * encoder shaft. This distance can be in any units you like, linear or angular.
+ * Set the distance per rotation of the encoder. This sets the multiplier used to determine the
+ * distance driven based on the rotation value from the encoder. Set this value based on the how
+ * far the mechanism travels in 1 rotation of the encoder, and factor in gearing reductions
+ * following the encoder shaft. This distance can be in any units you like, linear or angular.
*
* @param distancePerRotation the distance per rotation of the encoder
*/
public void setDistancePerRotation(double distancePerRotation) {
m_distancePerRotation = distancePerRotation;
-
- if (m_simDistancePerRotation != null) {
- m_simDistancePerRotation.set(distancePerRotation);
- }
}
/**
* Get the distance per rotation for this encoder.
*
- * @return The scale factor that will be used to convert rotation to useful
- * units.
+ * @return The scale factor that will be used to convert rotation to useful units.
*/
public double getDistancePerRotation() {
return m_distancePerRotation;
}
/**
- * Get the distance the sensor has driven since the last reset as scaled by the
- * value from {@link #setDistancePerRotation(double)}.
+ * Get the distance the sensor has driven since the last reset as scaled by the value from {@link
+ * #setDistancePerRotation(double)}.
*
* @return The distance driven since the last reset
*/
@@ -177,9 +169,7 @@
return m_dutyCycle.getFrequency();
}
- /**
- * Reset the Encoder distance to zero.
- */
+ /** Reset the Encoder distance to zero. */
public void reset() {
if (m_counter != null) {
m_counter.reset();
@@ -190,9 +180,9 @@
/**
* Get if the sensor is connected
*
- * <p>This uses the duty cycle frequency to determine if the sensor is connected.
- * By default, a value of 100 Hz is used as the threshold, and this value can be
- * changed with {@link #setConnectedFrequencyThreshold(int)}.
+ * <p>This uses the duty cycle frequency to determine if the sensor is connected. By default, a
+ * value of 100 Hz is used as the threshold, and this value can be changed with {@link
+ * #setConnectedFrequencyThreshold(int)}.
*
* @return true if the sensor is connected
*/
@@ -204,8 +194,7 @@
}
/**
- * Change the frequency threshold for detecting connection used by
- * {@link #isConnected()}.
+ * Change the frequency threshold for detecting connection used by {@link #isConnected()}.
*
* @param frequency the minimum frequency in Hz.
*/
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Encoder.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Encoder.java
index 125f769..200d713 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Encoder.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Encoder.java
@@ -1,21 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+
import edu.wpi.first.hal.EncoderJNI;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimDevice;
import edu.wpi.first.hal.util.AllocationException;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Class to read quadrature encoders.
@@ -30,11 +28,13 @@
* <p>All encoders will immediately start counting - reset() them if you need them to be zeroed
* before use.
*/
-public class Encoder implements CounterBase, PIDSource, Sendable, AutoCloseable {
+public class Encoder implements CounterBase, Sendable, AutoCloseable {
public enum IndexingType {
- kResetWhileHigh(0), kResetWhileLow(1), kResetOnFallingEdge(2), kResetOnRisingEdge(3);
+ kResetWhileHigh(0),
+ kResetWhileLow(1),
+ kResetOnFallingEdge(2),
+ kResetOnRisingEdge(3);
- @SuppressWarnings("MemberName")
public final int value;
IndexingType(int value) {
@@ -42,27 +42,19 @@
}
}
- /**
- * The a source.
- */
- @SuppressWarnings("MemberName")
+ /** The a source. */
protected DigitalSource m_aSource; // the A phase of the quad encoder
- /**
- * The b source.
- */
- @SuppressWarnings("MemberName")
+ /** The b source. */
protected DigitalSource m_bSource; // the B phase of the quad encoder
- /**
- * The index source.
- */
+ /** The index source. */
protected DigitalSource m_indexSource; // Index on some encoders
+
private boolean m_allocatedA;
private boolean m_allocatedB;
private boolean m_allocatedI;
- private PIDSourceType m_pidSource;
+ private final EncodingType m_encodingType;
- private int m_encoder; // the HAL encoder object
-
+ int m_encoder; // the HAL encoder object
/**
* Common initialization code for Encoders. This code allocates resources for Encoders and is
@@ -73,11 +65,14 @@
* @param reverseDirection If true, counts down instead of up (this is all relative)
*/
private void initEncoder(boolean reverseDirection, final EncodingType type) {
- m_encoder = EncoderJNI.initializeEncoder(m_aSource.getPortHandleForRouting(),
- m_aSource.getAnalogTriggerTypeForRouting(), m_bSource.getPortHandleForRouting(),
- m_bSource.getAnalogTriggerTypeForRouting(), reverseDirection, type.value);
-
- m_pidSource = PIDSourceType.kDisplacement;
+ m_encoder =
+ EncoderJNI.initializeEncoder(
+ m_aSource.getPortHandleForRouting(),
+ m_aSource.getAnalogTriggerTypeForRouting(),
+ m_bSource.getPortHandleForRouting(),
+ m_bSource.getAnalogTriggerTypeForRouting(),
+ reverseDirection,
+ type.value);
int fpgaIndex = getFPGAIndex();
HAL.report(tResourceType.kResourceType_Encoder, fpgaIndex + 1, type.value + 1);
@@ -89,10 +84,10 @@
*
* <p>The encoder will start counting immediately.
*
- * @param channelA The a channel DIO channel. 0-9 are on-board, 10-25 are on the MXP port
- * @param channelB The b channel DIO channel. 0-9 are on-board, 10-25 are on the MXP port
+ * @param channelA The a channel DIO channel. 0-9 are on-board, 10-25 are on the MXP port
+ * @param channelB The b channel DIO channel. 0-9 are on-board, 10-25 are on the MXP port
* @param reverseDirection represents the orientation of the encoder and inverts the output values
- * if necessary so forward represents positive values.
+ * if necessary so forward represents positive values.
*/
public Encoder(final int channelA, final int channelB, boolean reverseDirection) {
this(channelA, channelB, reverseDirection, EncodingType.k4X);
@@ -115,19 +110,21 @@
*
* <p>The encoder will start counting immediately.
*
- * @param channelA The a channel digital input channel.
- * @param channelB The b channel digital input channel.
+ * @param channelA The a channel digital input channel.
+ * @param channelB The b channel digital input channel.
* @param reverseDirection represents the orientation of the encoder and inverts the output values
- * if necessary so forward represents positive values.
- * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
- * selected, then an encoder FPGA object is used and the returned counts
- * will be 4x the encoder spec'd value since all rising and falling edges
- * are counted. If 1X or 2X are selected then a m_counter object will be
- * used and the returned value will either exactly match the spec'd count
- * or be double (2x) the spec'd count.
+ * if necessary so forward represents positive values.
+ * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
+ * selected, then an encoder FPGA object is used and the returned counts will be 4x the
+ * encoder spec'd value since all rising and falling edges are counted. If 1X or 2X are
+ * selected then a m_counter object will be used and the returned value will either exactly
+ * match the spec'd count or be double (2x) the spec'd count.
*/
- public Encoder(final int channelA, final int channelB, boolean reverseDirection,
- final EncodingType encodingType) {
+ public Encoder(
+ final int channelA,
+ final int channelB,
+ boolean reverseDirection,
+ final EncodingType encodingType) {
requireNonNullParam(encodingType, "encodingType", "Encoder");
m_allocatedA = true;
@@ -135,6 +132,7 @@
m_allocatedI = false;
m_aSource = new DigitalInput(channelA);
m_bSource = new DigitalInput(channelB);
+ m_encodingType = encodingType;
SendableRegistry.addChild(this, m_aSource);
SendableRegistry.addChild(this, m_bSource);
initEncoder(reverseDirection, encodingType);
@@ -146,14 +144,14 @@
*
* <p>The encoder will start counting immediately.
*
- * @param channelA The a channel digital input channel.
- * @param channelB The b channel digital input channel.
- * @param indexChannel The index channel digital input channel.
+ * @param channelA The a channel digital input channel.
+ * @param channelB The b channel digital input channel.
+ * @param indexChannel The index channel digital input channel.
* @param reverseDirection represents the orientation of the encoder and inverts the output values
- * if necessary so forward represents positive values.
+ * if necessary so forward represents positive values.
*/
- public Encoder(final int channelA, final int channelB, final int indexChannel,
- boolean reverseDirection) {
+ public Encoder(
+ final int channelA, final int channelB, final int indexChannel, boolean reverseDirection) {
this(channelA, channelB, reverseDirection);
m_allocatedI = true;
m_indexSource = new DigitalInput(indexChannel);
@@ -167,8 +165,8 @@
*
* <p>The encoder will start counting immediately.
*
- * @param channelA The a channel digital input channel.
- * @param channelB The b channel digital input channel.
+ * @param channelA The a channel digital input channel.
+ * @param channelB The b channel digital input channel.
* @param indexChannel The index channel digital input channel.
*/
public Encoder(final int channelA, final int channelB, final int indexChannel) {
@@ -182,10 +180,10 @@
*
* <p>The encoder will start counting immediately.
*
- * @param sourceA The source that should be used for the a channel.
- * @param sourceB the source that should be used for the b channel.
+ * @param sourceA The source that should be used for the a channel.
+ * @param sourceB the source that should be used for the b channel.
* @param reverseDirection represents the orientation of the encoder and inverts the output values
- * if necessary so forward represents positive values.
+ * if necessary so forward represents positive values.
*/
public Encoder(DigitalSource sourceA, DigitalSource sourceB, boolean reverseDirection) {
this(sourceA, sourceB, reverseDirection, EncodingType.k4X);
@@ -212,19 +210,21 @@
*
* <p>The encoder will start counting immediately.
*
- * @param sourceA The source that should be used for the a channel.
- * @param sourceB the source that should be used for the b channel.
+ * @param sourceA The source that should be used for the a channel.
+ * @param sourceB the source that should be used for the b channel.
* @param reverseDirection represents the orientation of the encoder and inverts the output values
- * if necessary so forward represents positive values.
- * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
- * selected, then an encoder FPGA object is used and the returned counts
- * will be 4x the encoder spec'd value since all rising and falling edges
- * are counted. If 1X or 2X are selected then a m_counter object will be
- * used and the returned value will either exactly match the spec'd count
- * or be double (2x) the spec'd count.
+ * if necessary so forward represents positive values.
+ * @param encodingType either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If 4X is
+ * selected, then an encoder FPGA object is used and the returned counts will be 4x the
+ * encoder spec'd value since all rising and falling edges are counted. If 1X or 2X are
+ * selected then a m_counter object will be used and the returned value will either exactly
+ * match the spec'd count or be double (2x) the spec'd count.
*/
- public Encoder(DigitalSource sourceA, DigitalSource sourceB, boolean reverseDirection,
- final EncodingType encodingType) {
+ public Encoder(
+ DigitalSource sourceA,
+ DigitalSource sourceB,
+ boolean reverseDirection,
+ final EncodingType encodingType) {
requireNonNullParam(sourceA, "sourceA", "Encoder");
requireNonNullParam(sourceB, "sourceB", "Encoder");
requireNonNullParam(encodingType, "encodingType", "Encoder");
@@ -232,6 +232,7 @@
m_allocatedA = false;
m_allocatedB = false;
m_allocatedI = false;
+ m_encodingType = encodingType;
m_aSource = sourceA;
m_bSource = sourceB;
initEncoder(reverseDirection, encodingType);
@@ -244,14 +245,17 @@
*
* <p>The encoder will start counting immediately.
*
- * @param sourceA The source that should be used for the a channel.
- * @param sourceB the source that should be used for the b channel.
- * @param indexSource the source that should be used for the index channel.
+ * @param sourceA The source that should be used for the a channel.
+ * @param sourceB the source that should be used for the b channel.
+ * @param indexSource the source that should be used for the index channel.
* @param reverseDirection represents the orientation of the encoder and inverts the output values
- * if necessary so forward represents positive values.
+ * if necessary so forward represents positive values.
*/
- public Encoder(DigitalSource sourceA, DigitalSource sourceB, DigitalSource indexSource,
- boolean reverseDirection) {
+ public Encoder(
+ DigitalSource sourceA,
+ DigitalSource sourceB,
+ DigitalSource indexSource,
+ boolean reverseDirection) {
this(sourceA, sourceB, reverseDirection);
m_allocatedI = false;
m_indexSource = indexSource;
@@ -265,8 +269,8 @@
*
* <p>The encoder will start counting immediately.
*
- * @param sourceA The source that should be used for the a channel.
- * @param sourceB the source that should be used for the b channel.
+ * @param sourceA The source that should be used for the a channel.
+ * @param sourceB the source that should be used for the b channel.
* @param indexSource the source that should be used for the index channel.
*/
public Encoder(DigitalSource sourceA, DigitalSource sourceB, DigitalSource indexSource) {
@@ -336,9 +340,7 @@
return EncoderJNI.getEncoder(m_encoder);
}
- /**
- * Reset the Encoder distance to zero. Resets the current count to zero on the encoder.
- */
+ /** Reset the Encoder distance to zero. Resets the current count to zero on the encoder. */
@Override
public void reset() {
EncoderJNI.resetEncoder(m_encoder);
@@ -367,7 +369,7 @@
* compensates for the decoding type.
*
* @param maxPeriod The maximum time between rising and falling edges before the FPGA will report
- * the device stopped. This is expressed in seconds.
+ * the device stopped. This is expressed in seconds.
*/
@Override
public void setMaxPeriod(double maxPeriod) {
@@ -420,7 +422,7 @@
* Set the minimum rate of the device before the hardware reports it stopped.
*
* @param minRate The minimum rate. The units are in distance per second as scaled by the value
- * from setDistancePerPulse().
+ * from setDistancePerPulse().
*/
public void setMinRate(double minRate) {
EncoderJNI.setEncoderMinRate(m_encoder, minRate);
@@ -481,39 +483,6 @@
}
/**
- * Set which parameter of the encoder you are using as a process control variable. The encoder
- * class supports the rate and distance parameters.
- *
- * @param pidSource An enum to select the parameter.
- */
- @Override
- public void setPIDSourceType(PIDSourceType pidSource) {
- m_pidSource = pidSource;
- }
-
- @Override
- public PIDSourceType getPIDSourceType() {
- return m_pidSource;
- }
-
- /**
- * Implement the PIDSource interface.
- *
- * @return The current value of the selected source parameter.
- */
- @Override
- public double pidGet() {
- switch (m_pidSource) {
- case kDisplacement:
- return getDistance();
- case kRate:
- return getRate();
- default:
- return 0.0;
- }
- }
-
- /**
* Set the index source for the encoder. When this source is activated, the encoder count
* automatically resets.
*
@@ -538,7 +507,7 @@
* resets.
*
* @param channel A DIO channel to set as the encoder index
- * @param type The state that will cause the encoder to reset
+ * @param type The state that will cause the encoder to reset
*/
public void setIndexSource(int channel, IndexingType type) {
if (m_allocatedI) {
@@ -555,11 +524,14 @@
* resets.
*
* @param source A digital source to set as the encoder index
- * @param type The state that will cause the encoder to reset
+ * @param type The state that will cause the encoder to reset
*/
public void setIndexSource(DigitalSource source, IndexingType type) {
- EncoderJNI.setEncoderIndexSource(m_encoder, source.getPortHandleForRouting(),
- source.getAnalogTriggerTypeForRouting(), type.value);
+ EncoderJNI.setEncoderIndexSource(
+ m_encoder,
+ source.getPortHandleForRouting(),
+ source.getAnalogTriggerTypeForRouting(),
+ type.value);
}
/**
@@ -571,6 +543,24 @@
EncoderJNI.setEncoderSimDevice(m_encoder, device.getNativeHandle());
}
+ /**
+ * Gets the decoding scale factor for scaling raw values to full counts.
+ *
+ * @return decoding scale factor
+ */
+ public double getDecodingScaleFactor() {
+ switch (m_encodingType) {
+ case k1X:
+ return 1.0;
+ case k2X:
+ return 0.5;
+ case k4X:
+ return 0.25;
+ default:
+ return 0.0;
+ }
+ }
+
@Override
public void initSendable(SendableBuilder builder) {
if (EncoderJNI.getEncoderEncodingType(m_encoder) == EncodingType.k4X.value) {
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Filesystem.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Filesystem.java
index c1327aa..98230db 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Filesystem.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Filesystem.java
@@ -1,27 +1,24 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import java.io.File;
/**
- * Class for interacting with the Filesystem, particularly, interacting with
- * FRC-related paths on the system, such as the launch and deploy directories.
+ * Class for interacting with the Filesystem, particularly, interacting with FRC-related paths on
+ * the system, such as the launch and deploy directories.
*
- * <p>This class is primarily used for obtaining resources in src/main/deploy, and
- * the RoboRIO path /home/lvuser in a simulation-compatible way.</p>
+ * <p>This class is primarily used for obtaining resources in src/main/deploy, and the RoboRIO path
+ * /home/lvuser in a simulation-compatible way.
*/
public final class Filesystem {
- private Filesystem() { }
+ private Filesystem() {}
/**
- * Obtains the current working path that the program was launched with.
- * This is analogous to the `pwd` command on unix.
+ * Obtains the current working path that the program was launched with. This is analogous to the
+ * `pwd` command on unix.
*
* @return The current working directory (launch directory)
*/
@@ -30,9 +27,8 @@
}
/**
- * Obtains the operating directory of the program. On the roboRIO, this is
- * /home/lvuser. In simulation, it is where the simulation was launched from
- * (`pwd`).
+ * Obtains the operating directory of the program. On the roboRIO, this is /home/lvuser. In
+ * simulation, it is where the simulation was launched from (`pwd`).
*
* @return The operating directory
*/
@@ -45,10 +41,10 @@
}
/**
- * Obtains the deploy directory of the program, which is the remote location
- * src/main/deploy is deployed to by default. On the roboRIO, this is
- * /home/lvuser/deploy. In simulation, it is where the simulation was launched
- * from, in the subdirectory "src/main/deploy" (`pwd`/src/main/deploy).
+ * Obtains the deploy directory of the program, which is the remote location src/main/deploy is
+ * deployed to by default. On the roboRIO, this is /home/lvuser/deploy. In simulation, it is where
+ * the simulation was launched from, in the subdirectory "src/main/deploy"
+ * (`pwd`/src/main/deploy).
*
* @return The deploy directory
*/
@@ -56,8 +52,8 @@
if (RobotBase.isReal()) {
return new File(getOperatingDirectory(), "deploy");
} else {
- return new File(getOperatingDirectory(), "src" + File.separator + "main"
- + File.separator + "deploy");
+ return new File(
+ getOperatingDirectory(), "src" + File.separator + "main" + File.separator + "deploy");
}
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/GearTooth.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/GearTooth.java
deleted file mode 100644
index 41f9d09..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/GearTooth.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Alias for counter class. Implement the gear tooth sensor supplied by FIRST. Currently there is no
- * reverse sensing on the gear tooth sensor, but in future versions we might implement the necessary
- * timing in the FPGA to sense direction.
- *
- * @deprecated The only sensor this works with is no longer available and no teams use it according
- * to FMS usage reporting.
- */
-@Deprecated(since = "2020", forRemoval = true)
-public class GearTooth extends Counter {
- private static final double kGearToothThreshold = 55e-6;
-
- /**
- * Common code called by the constructors.
- */
- public void enableDirectionSensing(boolean directionSensitive) {
- if (directionSensitive) {
- setPulseLengthMode(kGearToothThreshold);
- }
- }
-
- /**
- * Construct a GearTooth sensor given a channel.
- *
- * <p>No direction sensing is assumed.
- *
- * @param channel The GPIO channel that the sensor is connected to.
- */
- public GearTooth(final int channel) {
- this(channel, false);
- }
-
- /**
- * Construct a GearTooth sensor given a channel.
- *
- * @param channel The DIO channel that the sensor is connected to. 0-9 are on-board,
- * 10-25 are on the MXP port
- * @param directionSensitive True to enable the pulse length decoding in hardware to specify count
- * direction.
- */
- public GearTooth(final int channel, boolean directionSensitive) {
- super(channel);
- enableDirectionSensing(directionSensitive);
- if (directionSensitive) {
- HAL.report(tResourceType.kResourceType_GearTooth, channel + 1, 0, "D");
- } else {
- HAL.report(tResourceType.kResourceType_GearTooth, channel + 1, 0);
- }
- SendableRegistry.setName(this, "GearTooth", channel);
- }
-
- /**
- * Construct a GearTooth sensor given a digital input. This should be used when sharing digital
- * inputs.
- *
- * @param source An existing DigitalSource object (such as a DigitalInput)
- * @param directionSensitive True to enable the pulse length decoding in hardware to specify count
- * direction.
- */
- public GearTooth(DigitalSource source, boolean directionSensitive) {
- super(source);
- enableDirectionSensing(directionSensitive);
- if (directionSensitive) {
- HAL.report(tResourceType.kResourceType_GearTooth, source.getChannel() + 1, 0, "D");
- } else {
- HAL.report(tResourceType.kResourceType_GearTooth, source.getChannel() + 1, 0);
- }
- SendableRegistry.setName(this, "GearTooth", source.getChannel());
- }
-
- /**
- * Construct a GearTooth sensor given a digital input. This should be used when sharing digital
- * inputs.
- *
- * <p>No direction sensing is assumed.
- *
- * @param source An object that fully describes the input that the sensor is connected to.
- */
- public GearTooth(DigitalSource source) {
- this(source, false);
- }
-
- @Override
- public void initSendable(SendableBuilder builder) {
- super.initSendable(builder);
- builder.setSmartDashboardType("Gear Tooth");
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/GenericHID.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/GenericHID.java
index f573cb2..4903e00 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/GenericHID.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/GenericHID.java
@@ -1,26 +1,25 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+import edu.wpi.first.hal.HAL;
import java.util.HashMap;
import java.util.Map;
-import edu.wpi.first.hal.HAL;
-
/**
- * GenericHID Interface.
+ * Handle input from standard HID devices connected to the Driver Station.
+ *
+ * <p>This class handles standard input that comes from the Driver Station. Each time a value is
+ * requested the most recent value is returned. There is a single class instance for each device and
+ * the mapping of ports to hardware buttons depends on the code in the Driver Station.
*/
-public abstract class GenericHID {
- /**
- * Represents a rumble output on the JoyStick.
- */
+public class GenericHID {
+ /** Represents a rumble output on the JoyStick. */
public enum RumbleType {
- kLeftRumble, kRightRumble
+ kLeftRumble,
+ kRightRumble
}
public enum HIDType {
@@ -42,8 +41,8 @@
kHIDFlight(23),
kHID1stPerson(24);
- @SuppressWarnings("MemberName")
public final int value;
+
@SuppressWarnings("PMD.UseConcurrentHashMap")
private static final Map<Integer, HIDType> map = new HashMap<>();
@@ -62,109 +61,62 @@
}
}
- /**
- * Which hand the Human Interface Device is associated with.
- */
- public enum Hand {
- kLeft(0), kRight(1);
-
- @SuppressWarnings("MemberName")
- public final int value;
-
- Hand(int value) {
- this.value = value;
- }
- }
-
- private DriverStation m_ds;
private final int m_port;
private int m_outputs;
private short m_leftRumble;
private short m_rightRumble;
+ /**
+ * Construct an instance of a device.
+ *
+ * @param port The port index on the Driver Station that the device is plugged into.
+ */
public GenericHID(int port) {
- m_ds = DriverStation.getInstance();
m_port = port;
}
/**
- * Get the x position of the HID.
- *
- * @return the x position of the HID
- */
- public final double getX() {
- return getX(Hand.kRight);
- }
-
- /**
- * Get the x position of HID.
- *
- * @param hand which hand, left or right
- * @return the x position
- */
- public abstract double getX(Hand hand);
-
- /**
- * Get the y position of the HID.
- *
- * @return the y position
- */
- public final double getY() {
- return getY(Hand.kRight);
- }
-
- /**
- * Get the y position of the HID.
- *
- * @param hand which hand, left or right
- * @return the y position
- */
- public abstract double getY(Hand hand);
-
- /**
* Get the button value (starting at button 1).
*
* <p>The buttons are returned in a single 16 bit value with one bit representing the state of
* each button. The appropriate button is returned as a boolean value.
*
- * <p>This method returns true if the button is being held down at the time
- * that this method is being called.
+ * <p>This method returns true if the button is being held down at the time that this method is
+ * being called.
*
* @param button The button number to be read (starting at 1)
* @return The state of the button.
*/
public boolean getRawButton(int button) {
- return m_ds.getStickButton(m_port, (byte) button);
+ return DriverStation.getStickButton(m_port, (byte) button);
}
/**
- * Whether the button was pressed since the last check. Button indexes begin at
- * 1.
+ * Whether the button was pressed since the last check. Button indexes begin at 1.
*
- * <p>This method returns true if the button went from not pressed to held down
- * since the last time this method was called. This is useful if you only
- * want to call a function once when you press the button.
+ * <p>This method returns true if the button went from not pressed to held down since the last
+ * time this method was called. This is useful if you only want to call a function once when you
+ * press the button.
*
* @param button The button index, beginning at 1.
* @return Whether the button was pressed since the last check.
*/
public boolean getRawButtonPressed(int button) {
- return m_ds.getStickButtonPressed(m_port, (byte) button);
+ return DriverStation.getStickButtonPressed(m_port, (byte) button);
}
/**
- * Whether the button was released since the last check. Button indexes begin at
- * 1.
+ * Whether the button was released since the last check. Button indexes begin at 1.
*
- * <p>This method returns true if the button went from held down to not pressed
- * since the last time this method was called. This is useful if you only
- * want to call a function once when you release the button.
+ * <p>This method returns true if the button went from held down to not pressed since the last
+ * time this method was called. This is useful if you only want to call a function once when you
+ * release the button.
*
* @param button The button index, beginning at 1.
* @return Whether the button was released since the last check.
*/
public boolean getRawButtonReleased(int button) {
- return m_ds.getStickButtonReleased(m_port, button);
+ return DriverStation.getStickButtonReleased(m_port, button);
}
/**
@@ -174,7 +126,7 @@
* @return The value of the axis.
*/
public double getRawAxis(int axis) {
- return m_ds.getStickAxis(m_port, axis);
+ return DriverStation.getStickAxis(m_port, axis);
}
/**
@@ -183,13 +135,21 @@
* <p>The POV angles start at 0 in the up direction, and increase clockwise (eg right is 90,
* upper-left is 315).
*
- * @param pov The index of the POV to read (starting at 0)
+ * @param pov The index of the POV to read (starting at 0). Defaults to 0.
* @return the angle of the POV in degrees, or -1 if the POV is not pressed.
*/
public int getPOV(int pov) {
- return m_ds.getStickPOV(m_port, pov);
+ return DriverStation.getStickPOV(m_port, pov);
}
+ /**
+ * Get the angle in degrees of the default POV (index 0) on the HID.
+ *
+ * <p>The POV angles start at 0 in the up direction, and increase clockwise (eg right is 90,
+ * upper-left is 315).
+ *
+ * @return the angle of the POV in degrees, or -1 if the POV is not pressed.
+ */
public int getPOV() {
return getPOV(0);
}
@@ -200,21 +160,25 @@
* @return the number of axis for the current HID
*/
public int getAxisCount() {
- return m_ds.getStickAxisCount(m_port);
+ return DriverStation.getStickAxisCount(m_port);
}
/**
* For the current HID, return the number of POVs.
+ *
+ * @return the number of POVs for the current HID
*/
public int getPOVCount() {
- return m_ds.getStickPOVCount(m_port);
+ return DriverStation.getStickPOVCount(m_port);
}
/**
* For the current HID, return the number of buttons.
+ *
+ * @return the number of buttons for the current HID
*/
public int getButtonCount() {
- return m_ds.getStickButtonCount(m_port);
+ return DriverStation.getStickButtonCount(m_port);
}
/**
@@ -223,7 +187,7 @@
* @return true if the HID is connected
*/
public boolean isConnected() {
- return m_ds.isJoystickConnected(m_port);
+ return DriverStation.isJoystickConnected(m_port);
}
/**
@@ -232,7 +196,7 @@
* @return the type of the HID.
*/
public HIDType getType() {
- return HIDType.of(m_ds.getJoystickType(m_port));
+ return HIDType.of(DriverStation.getJoystickType(m_port));
}
/**
@@ -241,16 +205,17 @@
* @return the name of the HID.
*/
public String getName() {
- return m_ds.getJoystickName(m_port);
+ return DriverStation.getJoystickName(m_port);
}
/**
* Get the axis type of a joystick axis.
*
+ * @param axis The axis to read, starting at 0.
* @return the axis type of a joystick axis.
*/
public int getAxisType(int axis) {
- return m_ds.getJoystickAxisType(m_port, axis);
+ return DriverStation.getJoystickAxisType(m_port, axis);
}
/**
@@ -266,7 +231,7 @@
* Set a single HID output value for the HID.
*
* @param outputNumber The index of the output to set (1-32)
- * @param value The value to set the output to
+ * @param value The value to set the output to
*/
public void setOutput(int outputNumber, boolean value) {
m_outputs = (m_outputs & ~(1 << (outputNumber - 1))) | ((value ? 1 : 0) << (outputNumber - 1));
@@ -287,7 +252,7 @@
* Set the rumble output for the HID. The DS currently supports 2 rumble values, left rumble and
* right rumble.
*
- * @param type Which rumble value to set
+ * @param type Which rumble value to set
* @param value The normalized value (0 to 1) to set the rumble to
*/
public void setRumble(RumbleType type, double value) {
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/GyroBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/GyroBase.java
deleted file mode 100644
index 21330ce..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/GyroBase.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.wpilibj.interfaces.Gyro;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-
-/**
- * GyroBase is the common base class for Gyro implementations such as AnalogGyro.
- */
-public abstract class GyroBase implements Gyro, PIDSource, Sendable {
- private PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
-
- /**
- * Set which parameter of the gyro you are using as a process control variable. The Gyro class
- * supports the rate and displacement parameters
- *
- * @param pidSource An enum to select the parameter.
- */
- @Override
- public void setPIDSourceType(PIDSourceType pidSource) {
- m_pidSource = pidSource;
- }
-
- @Override
- public PIDSourceType getPIDSourceType() {
- return m_pidSource;
- }
-
- /**
- * Get the output of the gyro for use with PIDControllers. May be the angle or rate depending on
- * the set PIDSourceType
- *
- * @return the output according to the gyro
- */
- @Override
- public double pidGet() {
- switch (m_pidSource) {
- case kRate:
- return getRate();
- case kDisplacement:
- return getAngle();
- default:
- return 0.0;
- }
- }
-
- @Override
- public void initSendable(SendableBuilder builder) {
- builder.setSmartDashboardType("Gyro");
- builder.addDoubleProperty("Value", this::getAngle, null);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java
index 58b96aa..1d148a7 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/I2C.java
@@ -1,20 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.ByteBuffer;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.I2CJNI;
import edu.wpi.first.hal.util.BoundaryException;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import java.nio.ByteBuffer;
/**
* I2C bus interface class.
@@ -22,12 +18,11 @@
* <p>This class is intended to be used by sensor (and other I2C device) drivers. It probably should
* not be used directly.
*/
-@SuppressWarnings("PMD.GodClass")
public class I2C implements AutoCloseable {
public enum Port {
- kOnboard(0), kMXP(1);
+ kOnboard(0),
+ kMXP(1);
- @SuppressWarnings("MemberName")
public final int value;
Port(int value) {
@@ -41,7 +36,7 @@
/**
* Constructor.
*
- * @param port The I2C port the device is connected to.
+ * @param port The I2C port the device is connected to.
* @param deviceAddress The address of the device on the I2C bus.
*/
public I2C(Port port, int deviceAddress) {
@@ -53,6 +48,14 @@
HAL.report(tResourceType.kResourceType_I2C, deviceAddress);
}
+ public int getPort() {
+ return m_port;
+ }
+
+ public int getDeviceAddress() {
+ return m_deviceAddress;
+ }
+
@Override
public void close() {
I2CJNI.i2CClose(m_port);
@@ -62,18 +65,18 @@
* Generic transaction.
*
* <p>This is a lower-level interface to the I2C hardware giving you more control over each
- * transaction. If you intend to write multiple bytes in the same transaction and do not
- * plan to receive anything back, use writeBulk() instead. Calling this with a receiveSize
- * of 0 will result in an error.
+ * transaction. If you intend to write multiple bytes in the same transaction and do not plan to
+ * receive anything back, use writeBulk() instead. Calling this with a receiveSize of 0 will
+ * result in an error.
*
- * @param dataToSend Buffer of data to send as part of the transaction.
- * @param sendSize Number of bytes to send as part of the transaction.
+ * @param dataToSend Buffer of data to send as part of the transaction.
+ * @param sendSize Number of bytes to send as part of the transaction.
* @param dataReceived Buffer to read data into.
- * @param receiveSize Number of bytes to read from the device.
+ * @param receiveSize Number of bytes to read from the device.
* @return Transfer Aborted... false for success, true for aborted.
*/
- public synchronized boolean transaction(byte[] dataToSend, int sendSize,
- byte[] dataReceived, int receiveSize) {
+ public synchronized boolean transaction(
+ byte[] dataToSend, int sendSize, byte[] dataReceived, int receiveSize) {
if (dataToSend.length < sendSize) {
throw new IllegalArgumentException("dataToSend is too small, must be at least " + sendSize);
}
@@ -81,8 +84,14 @@
throw new IllegalArgumentException(
"dataReceived is too small, must be at least " + receiveSize);
}
- return I2CJNI.i2CTransactionB(m_port, (byte) m_deviceAddress, dataToSend,
- (byte) sendSize, dataReceived, (byte) receiveSize) < 0;
+ return I2CJNI.i2CTransactionB(
+ m_port,
+ (byte) m_deviceAddress,
+ dataToSend,
+ (byte) sendSize,
+ dataReceived,
+ (byte) receiveSize)
+ < 0;
}
/**
@@ -91,15 +100,15 @@
* <p>This is a lower-level interface to the I2C hardware giving you more control over each
* transaction.
*
- * @param dataToSend Buffer of data to send as part of the transaction.
- * @param sendSize Number of bytes to send as part of the transaction.
+ * @param dataToSend Buffer of data to send as part of the transaction.
+ * @param sendSize Number of bytes to send as part of the transaction.
* @param dataReceived Buffer to read data into.
- * @param receiveSize Number of bytes to read from the device.
+ * @param receiveSize Number of bytes to read from the device.
* @return Transfer Aborted... false for success, true for aborted.
*/
- @SuppressWarnings({"PMD.CyclomaticComplexity", "ByteBufferBackingArray"})
- public synchronized boolean transaction(ByteBuffer dataToSend, int sendSize,
- ByteBuffer dataReceived, int receiveSize) {
+ @SuppressWarnings("ByteBufferBackingArray")
+ public synchronized boolean transaction(
+ ByteBuffer dataToSend, int sendSize, ByteBuffer dataReceived, int receiveSize) {
if (dataToSend.hasArray() && dataReceived.hasArray()) {
return transaction(dataToSend.array(), sendSize, dataReceived.array(), receiveSize);
}
@@ -117,8 +126,14 @@
"dataReceived is too small, must be at least " + receiveSize);
}
- return I2CJNI.i2CTransaction(m_port, (byte) m_deviceAddress, dataToSend,
- (byte) sendSize, dataReceived, (byte) receiveSize) < 0;
+ return I2CJNI.i2CTransaction(
+ m_port,
+ (byte) m_deviceAddress,
+ dataToSend,
+ (byte) sendSize,
+ dataReceived,
+ (byte) receiveSize)
+ < 0;
}
/**
@@ -139,15 +154,14 @@
* <p>Write a single byte to a register on a device and wait until the transaction is complete.
*
* @param registerAddress The address of the register on the device to be written.
- * @param data The byte to write to the register on the device.
+ * @param data The byte to write to the register on the device.
* @return Transfer Aborted... false for success, true for aborted.
*/
public synchronized boolean write(int registerAddress, int data) {
byte[] buffer = new byte[2];
buffer[0] = (byte) registerAddress;
buffer[1] = (byte) data;
- return I2CJNI.i2CWriteB(m_port, (byte) m_deviceAddress, buffer,
- (byte) buffer.length) < 0;
+ return I2CJNI.i2CWriteB(m_port, (byte) m_deviceAddress, buffer, (byte) buffer.length) < 0;
}
/**
@@ -173,8 +187,7 @@
*/
public synchronized boolean writeBulk(byte[] data, int size) {
if (data.length < size) {
- throw new IllegalArgumentException(
- "buffer is too small, must be at least " + size);
+ throw new IllegalArgumentException("buffer is too small, must be at least " + size);
}
return I2CJNI.i2CWriteB(m_port, (byte) m_deviceAddress, data, (byte) size) < 0;
}
@@ -197,8 +210,7 @@
throw new IllegalArgumentException("must be a direct buffer");
}
if (data.capacity() < size) {
- throw new IllegalArgumentException(
- "buffer is too small, must be at least " + size);
+ throw new IllegalArgumentException("buffer is too small, must be at least " + size);
}
return I2CJNI.i2CWrite(m_port, (byte) m_deviceAddress, data, (byte) size) < 0;
@@ -211,8 +223,8 @@
* internally allowing you to read consecutive registers on a device in a single transaction.
*
* @param registerAddress The register to read first in the transaction.
- * @param count The number of bytes to read in the transaction.
- * @param buffer A pointer to the array of bytes to store the data read from the device.
+ * @param count The number of bytes to read in the transaction.
+ * @param buffer A pointer to the array of bytes to store the data read from the device.
* @return Transfer Aborted... false for success, true for aborted.
*/
public boolean read(int registerAddress, int count, byte[] buffer) {
@@ -240,8 +252,8 @@
* internally allowing you to read consecutive registers on a device in a single transaction.
*
* @param registerAddress The register to read first in the transaction.
- * @param count The number of bytes to read in the transaction.
- * @param buffer A buffer to store the data read from the device.
+ * @param count The number of bytes to read in the transaction.
+ * @param buffer A buffer to store the data read from the device.
* @return Transfer Aborted... false for success, true for aborted.
*/
@SuppressWarnings("ByteBufferBackingArray")
@@ -277,7 +289,7 @@
* <p>Read bytes from a device. This method does not write any data to prompt the device.
*
* @param buffer A pointer to the array of bytes to store the data read from the device.
- * @param count The number of bytes to read in the transaction.
+ * @param count The number of bytes to read in the transaction.
* @return Transfer Aborted... false for success, true for aborted.
*/
public boolean readOnly(byte[] buffer, int count) {
@@ -289,8 +301,7 @@
throw new IllegalArgumentException("buffer is too small, must be at least " + count);
}
- return I2CJNI.i2CReadB(m_port, (byte) m_deviceAddress, buffer,
- (byte) count) < 0;
+ return I2CJNI.i2CReadB(m_port, (byte) m_deviceAddress, buffer, (byte) count) < 0;
}
/**
@@ -299,14 +310,13 @@
* <p>Read bytes from a device. This method does not write any data to prompt the device.
*
* @param buffer A pointer to the array of bytes to store the data read from the device.
- * @param count The number of bytes to read in the transaction.
+ * @param count The number of bytes to read in the transaction.
* @return Transfer Aborted... false for success, true for aborted.
*/
@SuppressWarnings("ByteBufferBackingArray")
public boolean readOnly(ByteBuffer buffer, int count) {
if (count < 1) {
- throw new BoundaryException("Value must be at least 1, " + count
- + " given");
+ throw new BoundaryException("Value must be at least 1, " + count + " given");
}
if (buffer.hasArray()) {
@@ -320,8 +330,7 @@
throw new IllegalArgumentException("buffer is too small, must be at least " + count);
}
- return I2CJNI.i2CRead(m_port, (byte) m_deviceAddress, buffer, (byte) count)
- < 0;
+ return I2CJNI.i2CRead(m_port, (byte) m_deviceAddress, buffer, (byte) count) < 0;
}
/*
@@ -343,13 +352,12 @@
* expected value.
*
* @param registerAddress The base register to start reading from the device.
- * @param count The size of the field to be verified.
- * @param expected A buffer containing the values expected from the device.
+ * @param count The size of the field to be verified.
+ * @param expected A buffer containing the values expected from the device.
* @return true if the sensor was verified to be connected
* @pre The device must support and be configured to use register auto-increment.
*/
- public boolean verifySensor(int registerAddress, int count,
- byte[] expected) {
+ public boolean verifySensor(int registerAddress, int count, byte[] expected) {
// TODO: Make use of all 7 read bytes
byte[] dataToSend = new byte[1];
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptHandlerFunction.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptHandlerFunction.java
deleted file mode 100644
index 6fd807b..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptHandlerFunction.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.InterruptJNI.InterruptJNIHandlerFunction;
-
-
-/**
- * It is recommended that you use this class in conjunction with classes from {@link
- * java.util.concurrent.atomic} as these objects are all thread safe.
- *
- * @param <T> The type of the parameter that should be returned to the the method {@link
- * #interruptFired(int, Object)}
- */
-public abstract class InterruptHandlerFunction<T> {
- /**
- * The entry point for the interrupt. When the interrupt fires the {@link #apply(int, Object)}
- * method is called. The outer class is provided as an interface to allow the implementer to pass
- * a generic object to the interrupt fired method.
- */
- private class Function implements InterruptJNIHandlerFunction {
- @SuppressWarnings("unchecked")
- @Override
- public void apply(int interruptAssertedMask, Object param) {
- interruptFired(interruptAssertedMask, (T) param);
- }
- }
-
- final Function m_function = new Function();
-
- /**
- * This method is run every time an interrupt is fired.
- *
- * @param interruptAssertedMask Interrupt Mask
- * @param param The parameter provided by overriding the {@link
- * #overridableParameter()} method.
- */
- public abstract void interruptFired(int interruptAssertedMask, T param);
-
-
- /**
- * Override this method if you would like to pass a specific parameter to the {@link
- * #interruptFired(int, Object)} when it is fired by the interrupt. This method is called once
- * when {@link InterruptableSensorBase#requestInterrupts(InterruptHandlerFunction)} is run.
- *
- * @return The object that should be passed to the interrupt when it runs
- */
- public T overridableParameter() {
- return null;
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptableSensorBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptableSensorBase.java
deleted file mode 100644
index 8fb734b..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/InterruptableSensorBase.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import java.util.function.Consumer;
-
-import edu.wpi.first.hal.InterruptJNI;
-import edu.wpi.first.hal.util.AllocationException;
-
-
-/**
- * Base for sensors to be used with interrupts.
- */
-public abstract class InterruptableSensorBase implements AutoCloseable {
- @SuppressWarnings("JavadocMethod")
- public enum WaitResult {
- kTimeout(0x0), kRisingEdge(0x1), kFallingEdge(0x100), kBoth(0x101);
-
- @SuppressWarnings("MemberName")
- public final int value;
-
- WaitResult(int value) {
- this.value = value;
- }
-
- public static WaitResult getValue(boolean rising, boolean falling) {
- if (rising && falling) {
- return kBoth;
- } else if (rising) {
- return kRisingEdge;
- } else if (falling) {
- return kFallingEdge;
- } else {
- return kTimeout;
- }
- }
- }
-
- /**
- * The interrupt resource.
- */
- protected int m_interrupt = InterruptJNI.HalInvalidHandle;
-
- /**
- * Flags if the interrupt being allocated is synchronous.
- */
- protected boolean m_isSynchronousInterrupt;
-
- /**
- * Create a new InterrupatableSensorBase.
- */
- public InterruptableSensorBase() {
- m_interrupt = 0;
- }
-
- @Override
- public void close() {
- if (m_interrupt != 0) {
- cancelInterrupts();
- }
- }
-
- /**
- * If this is an analog trigger.
- *
- * @return true if this is an analog trigger.
- */
- public abstract int getAnalogTriggerTypeForRouting();
-
- /**
- * The channel routing number.
- *
- * @return channel routing number
- */
- public abstract int getPortHandleForRouting();
-
- /**
- * Request one of the 8 interrupts asynchronously on this digital input.
- *
- * @param handler The {@link Consumer} that will be called whenever there is an interrupt on this
- * device. Request interrupts in synchronous mode where the user program interrupt
- * handler will be called when an interrupt occurs. The default is interrupt on
- * rising edges only.
- */
- public void requestInterrupts(Consumer<WaitResult> handler) {
- if (m_interrupt != 0) {
- throw new AllocationException("The interrupt has already been allocated");
- }
-
- allocateInterrupts(false);
-
- assert m_interrupt != 0;
-
- InterruptJNI.requestInterrupts(m_interrupt, getPortHandleForRouting(),
- getAnalogTriggerTypeForRouting());
- setUpSourceEdge(true, false);
- InterruptJNI.attachInterruptHandler(m_interrupt, (mask, obj) -> {
- // Rising edge result is the interrupt bit set in the byte 0xFF
- // Falling edge result is the interrupt bit set in the byte 0xFF00
- boolean rising = (mask & 0xFF) != 0;
- boolean falling = (mask & 0xFF00) != 0;
- handler.accept(WaitResult.getValue(rising, falling));
- }, null);
- }
-
- /**
- * Request one of the 8 interrupts asynchronously on this digital input.
- *
- * @param handler The {@link InterruptHandlerFunction} that contains the method {@link
- * InterruptHandlerFunction#interruptFired(int, Object)} that will be called
- * whenever there is an interrupt on this device. Request interrupts in synchronous
- * mode where the user program interrupt handler will be called when an interrupt
- * occurs. The default is interrupt on rising edges only.
- */
- public void requestInterrupts(InterruptHandlerFunction<?> handler) {
- if (m_interrupt != 0) {
- throw new AllocationException("The interrupt has already been allocated");
- }
-
- allocateInterrupts(false);
-
- assert m_interrupt != 0;
-
- InterruptJNI.requestInterrupts(m_interrupt, getPortHandleForRouting(),
- getAnalogTriggerTypeForRouting());
- setUpSourceEdge(true, false);
- InterruptJNI.attachInterruptHandler(m_interrupt, handler.m_function,
- handler.overridableParameter());
- }
-
- /**
- * Request one of the 8 interrupts synchronously on this digital input. Request interrupts in
- * synchronous mode where the user program will have to explicitly wait for the interrupt to occur
- * using {@link #waitForInterrupt}. The default is interrupt on rising edges only.
- */
- public void requestInterrupts() {
- if (m_interrupt != 0) {
- throw new AllocationException("The interrupt has already been allocated");
- }
-
- allocateInterrupts(true);
-
- assert m_interrupt != 0;
-
- InterruptJNI.requestInterrupts(m_interrupt, getPortHandleForRouting(),
- getAnalogTriggerTypeForRouting());
- setUpSourceEdge(true, false);
-
- }
-
- /**
- * Allocate the interrupt.
- *
- * @param watcher true if the interrupt should be in synchronous mode where the user program will
- * have to explicitly wait for the interrupt to occur.
- */
- protected void allocateInterrupts(boolean watcher) {
- m_isSynchronousInterrupt = watcher;
-
- m_interrupt = InterruptJNI.initializeInterrupts(watcher);
- }
-
- /**
- * Cancel interrupts on this device. This deallocates all the chipobject structures and disables
- * any interrupts.
- */
- public void cancelInterrupts() {
- if (m_interrupt == 0) {
- throw new IllegalStateException("The interrupt is not allocated.");
- }
- InterruptJNI.cleanInterrupts(m_interrupt);
- m_interrupt = 0;
- }
-
- /**
- * In synchronous mode, wait for the defined interrupt to occur.
- *
- * @param timeout Timeout in seconds
- * @param ignorePrevious If true, ignore interrupts that happened before waitForInterrupt was
- * called.
- * @return Result of the wait.
- */
- public WaitResult waitForInterrupt(double timeout, boolean ignorePrevious) {
- if (m_interrupt == 0) {
- throw new IllegalStateException("The interrupt is not allocated.");
- }
- int result = InterruptJNI.waitForInterrupt(m_interrupt, timeout, ignorePrevious);
-
- // Rising edge result is the interrupt bit set in the byte 0xFF
- // Falling edge result is the interrupt bit set in the byte 0xFF00
- // Set any bit set to be true for that edge, and AND the 2 results
- // together to match the existing enum for all interrupts
- boolean rising = (result & 0xFF) != 0;
- boolean falling = (result & 0xFF00) != 0;
- return WaitResult.getValue(rising, falling);
- }
-
- /**
- * In synchronous mode, wait for the defined interrupt to occur.
- *
- * @param timeout Timeout in seconds
- * @return Result of the wait.
- */
- public WaitResult waitForInterrupt(double timeout) {
- return waitForInterrupt(timeout, true);
- }
-
- /**
- * Enable interrupts to occur on this input. Interrupts are disabled when the RequestInterrupt
- * call is made. This gives time to do the setup of the other options before starting to field
- * interrupts.
- */
- public void enableInterrupts() {
- if (m_interrupt == 0) {
- throw new IllegalStateException("The interrupt is not allocated.");
- }
- if (m_isSynchronousInterrupt) {
- throw new IllegalStateException("You do not need to enable synchronous interrupts");
- }
- InterruptJNI.enableInterrupts(m_interrupt);
- }
-
- /**
- * Disable Interrupts without without deallocating structures.
- */
- public void disableInterrupts() {
- if (m_interrupt == 0) {
- throw new IllegalStateException("The interrupt is not allocated.");
- }
- if (m_isSynchronousInterrupt) {
- throw new IllegalStateException("You can not disable synchronous interrupts");
- }
- InterruptJNI.disableInterrupts(m_interrupt);
- }
-
- /**
- * Return the timestamp for the rising interrupt that occurred most recently. This is in the same
- * time domain as getClock(). The rising-edge interrupt should be enabled with {@link
- * #setUpSourceEdge}.
- *
- * @return Timestamp in seconds since boot.
- */
- public double readRisingTimestamp() {
- if (m_interrupt == 0) {
- throw new IllegalStateException("The interrupt is not allocated.");
- }
- return InterruptJNI.readInterruptRisingTimestamp(m_interrupt) * 1e-6;
- }
-
- /**
- * Return the timestamp for the falling interrupt that occurred most recently. This is in the same
- * time domain as getClock(). The falling-edge interrupt should be enabled with {@link
- * #setUpSourceEdge}.
- *
- * @return Timestamp in seconds since boot.
- */
- public double readFallingTimestamp() {
- if (m_interrupt == 0) {
- throw new IllegalStateException("The interrupt is not allocated.");
- }
- return InterruptJNI.readInterruptFallingTimestamp(m_interrupt) * 1e-6;
- }
-
- /**
- * Set which edge to trigger interrupts on.
- *
- * @param risingEdge true to interrupt on rising edge
- * @param fallingEdge true to interrupt on falling edge
- */
- public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
- if (m_interrupt != 0) {
- InterruptJNI.setInterruptUpSourceEdge(m_interrupt, risingEdge,
- fallingEdge);
- } else {
- throw new IllegalArgumentException("You must call RequestInterrupts before setUpSourceEdge");
- }
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobot.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobot.java
deleted file mode 100644
index 66079a8..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobot.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tInstances;
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-
-/**
- * IterativeRobot implements the IterativeRobotBase robot program framework.
- *
- * <p>The IterativeRobot class is intended to be subclassed by a user creating a robot program.
- *
- * <p>periodic() functions from the base class are called each time a new packet is received from
- * the driver station.
- *
- * @deprecated Use TimedRobot instead. It's a drop-in replacement that provides more regular
- * execution periods.
- */
-@Deprecated
-public class IterativeRobot extends IterativeRobotBase {
- private static final double kPacketPeriod = 0.02;
- private volatile boolean m_exit;
-
- /**
- * Create a new IterativeRobot.
- */
- public IterativeRobot() {
- super(kPacketPeriod);
-
- HAL.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Iterative);
- }
-
- /**
- * Provide an alternate "main loop" via startCompetition().
- */
- @Override
- public void startCompetition() {
- robotInit();
-
- if (isSimulation()) {
- simulationInit();
- }
-
- // Tell the DS that the robot is ready to be enabled
- HAL.observeUserProgramStarting();
-
- // Loop forever, calling the appropriate mode-dependent function
- while (!Thread.currentThread().isInterrupted()) {
- // Wait for new data to arrive
- m_ds.waitForData();
- if (m_exit) {
- break;
- }
-
- loopFunc();
- }
- }
-
- /**
- * Ends the main loop in startCompetition().
- */
- @Override
- public void endCompetition() {
- m_exit = true;
- m_ds.wakeupWaitForData();
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobotBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobotBase.java
index daa5bdb..a8c92a6 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobotBase.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/IterativeRobotBase.java
@@ -1,13 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.HAL;
+import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
@@ -24,27 +22,37 @@
*
* <p>robotInit() -- provide for initialization at robot power-on
*
- * <p>init() functions -- each of the following functions is called once when the
- * appropriate mode is entered:
- * - disabledInit() -- called each and every time disabled is entered from
- * another mode
- * - autonomousInit() -- called each and every time autonomous is entered from
- * another mode
- * - teleopInit() -- called each and every time teleop is entered from
- * another mode
- * - testInit() -- called each and every time test is entered from
- * another mode
+ * <p>init() functions -- each of the following functions is called once when the appropriate mode
+ * is entered:
+ *
+ * <ul>
+ * <li>disabledInit() -- called each and every time disabled is entered from another mode
+ * <li>autonomousInit() -- called each and every time autonomous is entered from another mode
+ * <li>teleopInit() -- called each and every time teleop is entered from another mode
+ * <li>testInit() -- called each and every time test is entered from another mode
+ * </ul>
*
* <p>periodic() functions -- each of these functions is called on an interval:
- * - robotPeriodic()
- * - disabledPeriodic()
- * - autonomousPeriodic()
- * - teleopPeriodic()
- * - testPeriodic()
+ *
+ * <ul>
+ * <li>robotPeriodic()
+ * <li>disabledPeriodic()
+ * <li>autonomousPeriodic()
+ * <li>teleopPeriodic()
+ * <li>testPeriodic()
+ * </ul>
+ *
+ * <p>final() functions -- each of the following functions is called once when the appropriate mode
+ * is exited:
+ *
+ * <ul>
+ * <li>disabledExit() -- called each and every time disabled is exited
+ * <li>autonomousExit() -- called each and every time autonomous is exited
+ * <li>teleopExit() -- called each and every time teleop is exited
+ * <li>testExit() -- called each and every time test is exited
+ * </ul>
*/
public abstract class IterativeRobotBase extends RobotBase {
- protected double m_period;
-
private enum Mode {
kNone,
kDisabled,
@@ -53,8 +61,11 @@
kTest
}
+ private final DSControlWord m_word = new DSControlWord();
private Mode m_lastMode = Mode.kNone;
+ private final double m_period;
private final Watchdog m_watchdog;
+ private boolean m_ntFlushEnabled;
/**
* Constructor for IterativeRobotBase.
@@ -66,9 +77,7 @@
m_watchdog = new Watchdog(period, this::printLoopOverrunMessage);
}
- /**
- * Provide an alternate "main loop" via startCompetition().
- */
+ /** Provide an alternate "main loop" via startCompetition(). */
@Override
public abstract void startCompetition();
@@ -84,21 +93,16 @@
* until RobotInit() exits. Code in RobotInit() that waits for enable will cause the robot to
* never indicate that the code is ready, causing the robot to be bypassed in a match.
*/
- public void robotInit() {
- System.out.println("Default robotInit() method... Override me!");
- }
+ public void robotInit() {}
/**
* Robot-wide simulation initialization code should go here.
*
- * <p>Users should override this method for default Robot-wide simulation
- * related initialization which will be called when the robot is first
- * started. It will be called exactly one time after RobotInit is called
- * only when the robot is in simulation.
+ * <p>Users should override this method for default Robot-wide simulation related initialization
+ * which will be called when the robot is first started. It will be called exactly one time after
+ * RobotInit is called only when the robot is in simulation.
*/
- public void simulationInit() {
- System.out.println("Default simulationInit() method... Override me!");
- }
+ public void simulationInit() {}
/**
* Initialization code for disabled mode should go here.
@@ -106,9 +110,7 @@
* <p>Users should override this method for initialization code which will be called each time the
* robot enters disabled mode.
*/
- public void disabledInit() {
- System.out.println("Default disabledInit() method... Override me!");
- }
+ public void disabledInit() {}
/**
* Initialization code for autonomous mode should go here.
@@ -116,9 +118,7 @@
* <p>Users should override this method for initialization code which will be called each time the
* robot enters autonomous mode.
*/
- public void autonomousInit() {
- System.out.println("Default autonomousInit() method... Override me!");
- }
+ public void autonomousInit() {}
/**
* Initialization code for teleop mode should go here.
@@ -126,9 +126,7 @@
* <p>Users should override this method for initialization code which will be called each time the
* robot enters teleop mode.
*/
- public void teleopInit() {
- System.out.println("Default teleopInit() method... Override me!");
- }
+ public void teleopInit() {}
/**
* Initialization code for test mode should go here.
@@ -137,17 +135,13 @@
* robot enters test mode.
*/
@SuppressWarnings("PMD.JUnit4TestShouldUseTestAnnotation")
- public void testInit() {
- System.out.println("Default testInit() method... Override me!");
- }
+ public void testInit() {}
/* ----------- Overridable periodic code ----------------- */
private boolean m_rpFirstRun = true;
- /**
- * Periodic code for all robot modes should go here.
- */
+ /** Periodic code for all robot modes should go here. */
public void robotPeriodic() {
if (m_rpFirstRun) {
System.out.println("Default robotPeriodic() method... Override me!");
@@ -171,9 +165,7 @@
private boolean m_dpFirstRun = true;
- /**
- * Periodic code for disabled mode should go here.
- */
+ /** Periodic code for disabled mode should go here. */
public void disabledPeriodic() {
if (m_dpFirstRun) {
System.out.println("Default disabledPeriodic() method... Override me!");
@@ -183,9 +175,7 @@
private boolean m_apFirstRun = true;
- /**
- * Periodic code for autonomous mode should go here.
- */
+ /** Periodic code for autonomous mode should go here. */
public void autonomousPeriodic() {
if (m_apFirstRun) {
System.out.println("Default autonomousPeriodic() method... Override me!");
@@ -195,9 +185,7 @@
private boolean m_tpFirstRun = true;
- /**
- * Periodic code for teleop mode should go here.
- */
+ /** Periodic code for teleop mode should go here. */
public void teleopPeriodic() {
if (m_tpFirstRun) {
System.out.println("Default teleopPeriodic() method... Override me!");
@@ -207,9 +195,7 @@
private boolean m_tmpFirstRun = true;
- /**
- * Periodic code for test mode should go here.
- */
+ /** Periodic code for test mode should go here. */
@SuppressWarnings("PMD.JUnit4TestShouldUseTestAnnotation")
public void testPeriodic() {
if (m_tmpFirstRun) {
@@ -218,64 +204,122 @@
}
}
- @SuppressWarnings("PMD.CyclomaticComplexity")
+ /**
+ * Exit code for disabled mode should go here.
+ *
+ * <p>Users should override this method for code which will be called each time the robot exits
+ * disabled mode.
+ */
+ public void disabledExit() {}
+
+ /**
+ * Exit code for autonomous mode should go here.
+ *
+ * <p>Users should override this method for code which will be called each time the robot exits
+ * autonomous mode.
+ */
+ public void autonomousExit() {}
+
+ /**
+ * Exit code for teleop mode should go here.
+ *
+ * <p>Users should override this method for code which will be called each time the robot exits
+ * teleop mode.
+ */
+ public void teleopExit() {}
+
+ /**
+ * Exit code for test mode should go here.
+ *
+ * <p>Users should override this method for code which will be called each time the robot exits
+ * test mode.
+ */
+ @SuppressWarnings("PMD.JUnit4TestShouldUseTestAnnotation")
+ public void testExit() {}
+
+ /**
+ * Enables or disables flushing NetworkTables every loop iteration. By default, this is disabled.
+ *
+ * @param enabled True to enable, false to disable
+ */
+ public void setNetworkTablesFlushEnabled(boolean enabled) {
+ m_ntFlushEnabled = enabled;
+ }
+
+ /**
+ * Gets time period between calls to Periodic() functions.
+ *
+ * @return The time period between calls to Periodic() functions.
+ */
+ public double getPeriod() {
+ return m_period;
+ }
+
protected void loopFunc() {
m_watchdog.reset();
- // Call the appropriate function depending upon the current robot mode
- if (isDisabled()) {
- // Call DisabledInit() if we are now just entering disabled mode from either a different mode
- // or from power-on.
- if (m_lastMode != Mode.kDisabled) {
+ // Get current mode
+ m_word.update();
+ Mode mode = Mode.kNone;
+ if (m_word.isDisabled()) {
+ mode = Mode.kDisabled;
+ } else if (m_word.isAutonomous()) {
+ mode = Mode.kAutonomous;
+ } else if (m_word.isTeleop()) {
+ mode = Mode.kTeleop;
+ } else if (m_word.isTest()) {
+ mode = Mode.kTest;
+ }
+
+ // If mode changed, call mode exit and entry functions
+ if (m_lastMode != mode) {
+ // Call last mode's exit function
+ if (m_lastMode == Mode.kDisabled) {
+ disabledExit();
+ } else if (m_lastMode == Mode.kAutonomous) {
+ autonomousExit();
+ } else if (m_lastMode == Mode.kTeleop) {
+ teleopExit();
+ } else if (m_lastMode == Mode.kTest) {
LiveWindow.setEnabled(false);
Shuffleboard.disableActuatorWidgets();
+ testExit();
+ }
+
+ // Call current mode's entry function
+ if (mode == Mode.kDisabled) {
disabledInit();
m_watchdog.addEpoch("disabledInit()");
- m_lastMode = Mode.kDisabled;
- }
-
- HAL.observeUserProgramDisabled();
- disabledPeriodic();
- m_watchdog.addEpoch("disablePeriodic()");
- } else if (isAutonomous()) {
- // Call AutonomousInit() if we are now just entering autonomous mode from either a different
- // mode or from power-on.
- if (m_lastMode != Mode.kAutonomous) {
- LiveWindow.setEnabled(false);
- Shuffleboard.disableActuatorWidgets();
+ } else if (mode == Mode.kAutonomous) {
autonomousInit();
m_watchdog.addEpoch("autonomousInit()");
- m_lastMode = Mode.kAutonomous;
- }
-
- HAL.observeUserProgramAutonomous();
- autonomousPeriodic();
- m_watchdog.addEpoch("autonomousPeriodic()");
- } else if (isOperatorControl()) {
- // Call TeleopInit() if we are now just entering teleop mode from either a different mode or
- // from power-on.
- if (m_lastMode != Mode.kTeleop) {
- LiveWindow.setEnabled(false);
- Shuffleboard.disableActuatorWidgets();
+ } else if (mode == Mode.kTeleop) {
teleopInit();
m_watchdog.addEpoch("teleopInit()");
- m_lastMode = Mode.kTeleop;
- }
-
- HAL.observeUserProgramTeleop();
- teleopPeriodic();
- m_watchdog.addEpoch("teleopPeriodic()");
- } else {
- // Call TestInit() if we are now just entering test mode from either a different mode or from
- // power-on.
- if (m_lastMode != Mode.kTest) {
+ } else if (mode == Mode.kTest) {
LiveWindow.setEnabled(true);
Shuffleboard.enableActuatorWidgets();
testInit();
m_watchdog.addEpoch("testInit()");
- m_lastMode = Mode.kTest;
}
+ m_lastMode = mode;
+ }
+
+ // Call the appropriate function depending upon the current robot mode
+ if (mode == Mode.kDisabled) {
+ HAL.observeUserProgramDisabled();
+ disabledPeriodic();
+ m_watchdog.addEpoch("disabledPeriodic()");
+ } else if (mode == Mode.kAutonomous) {
+ HAL.observeUserProgramAutonomous();
+ autonomousPeriodic();
+ m_watchdog.addEpoch("autonomousPeriodic()");
+ } else if (mode == Mode.kTeleop) {
+ HAL.observeUserProgramTeleop();
+ teleopPeriodic();
+ m_watchdog.addEpoch("teleopPeriodic()");
+ } else {
HAL.observeUserProgramTest();
testPeriodic();
m_watchdog.addEpoch("testPeriodic()");
@@ -292,12 +336,19 @@
m_watchdog.addEpoch("Shuffleboard.update()");
if (isSimulation()) {
+ HAL.simPeriodicBefore();
simulationPeriodic();
+ HAL.simPeriodicAfter();
m_watchdog.addEpoch("simulationPeriodic()");
}
m_watchdog.disable();
+ // Flush NetworkTables
+ if (m_ntFlushEnabled) {
+ NetworkTableInstance.getDefault().flush();
+ }
+
// Warn on loop time overruns
if (m_watchdog.isExpired()) {
m_watchdog.printEpochs();
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Jaguar.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Jaguar.java
deleted file mode 100644
index 8ce7b7d..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Jaguar.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Texas Instruments / Vex Robotics Jaguar Speed Controller as a PWM device.
- *
- * <p>Note that the Jaguar uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the Jaguar User Manual
- * available from Vex.
- *
- * <p><ul>
- * <li>2.310ms = full "forward"
- * <li>1.550ms = the "high end" of the deadband range
- * <li>1.507ms = center of the deadband range (off)
- * <li>1.454ms = the "low end" of the deadband range
- * <li>0.697ms = full "reverse"
- * </ul>
- */
-public class Jaguar extends PWMSpeedController {
- /**
- * Constructor.
- *
- * @param channel The PWM channel that the Jaguar is attached to. 0-9 are on-board, 10-19 are on
- * the MXP port
- */
- public Jaguar(final int channel) {
- super(channel);
-
- setBounds(2.31, 1.55, 1.507, 1.454, 0.697);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_Jaguar, getChannel() + 1);
- SendableRegistry.setName(this, "Jaguar", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java
index a83a346..e9b09a9 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Joystick.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -11,7 +8,7 @@
import edu.wpi.first.hal.HAL;
/**
- * Handle input from standard Joysticks connected to the Driver Station.
+ * Handle input from Flight Joysticks connected to the Driver Station.
*
* <p>This class handles standard input that comes from the Driver Station. Each time a value is
* requested the most recent value is returned. There is a single class instance for each joystick
@@ -24,13 +21,14 @@
public static final byte kDefaultTwistChannel = 2;
public static final byte kDefaultThrottleChannel = 3;
- /**
- * Represents an analog axis on a joystick.
- */
+ /** Represents an analog axis on a joystick. */
public enum AxisType {
- kX(0), kY(1), kZ(2), kTwist(3), kThrottle(4);
+ kX(0),
+ kY(1),
+ kZ(2),
+ kTwist(3),
+ kThrottle(4);
- @SuppressWarnings("MemberName")
public final int value;
AxisType(int value) {
@@ -38,13 +36,11 @@
}
}
- /**
- * Represents a digital button on a joystick.
- */
+ /** Represents a digital button on a joystick. */
public enum ButtonType {
- kTrigger(1), kTop(2);
+ kTrigger(1),
+ kTop(2);
- @SuppressWarnings("MemberName")
public final int value;
ButtonType(int value) {
@@ -52,50 +48,21 @@
}
}
- /**
- * Represents a digital button on a joystick.
- */
- private enum Button {
- kTrigger(1), kTop(2);
-
- @SuppressWarnings("MemberName")
- public final int value;
-
- Button(int value) {
- this.value = value;
- }
- }
+ private final byte[] m_axes = new byte[AxisType.values().length];
/**
- * Represents an analog axis on a joystick.
- */
- private enum Axis {
- kX(0), kY(1), kZ(2), kTwist(3), kThrottle(4), kNumAxes(5);
-
- @SuppressWarnings("MemberName")
- public final int value;
-
- Axis(int value) {
- this.value = value;
- }
- }
-
- private final byte[] m_axes = new byte[Axis.kNumAxes.value];
-
- /**
- * Construct an instance of a joystick. The joystick index is the USB port on the drivers
- * station.
+ * Construct an instance of a joystick.
*
- * @param port The port on the Driver Station that the joystick is plugged into.
+ * @param port The port index on the Driver Station that the joystick is plugged into.
*/
public Joystick(final int port) {
super(port);
- m_axes[Axis.kX.value] = kDefaultXChannel;
- m_axes[Axis.kY.value] = kDefaultYChannel;
- m_axes[Axis.kZ.value] = kDefaultZChannel;
- m_axes[Axis.kTwist.value] = kDefaultTwistChannel;
- m_axes[Axis.kThrottle.value] = kDefaultThrottleChannel;
+ m_axes[AxisType.kX.value] = kDefaultXChannel;
+ m_axes[AxisType.kY.value] = kDefaultYChannel;
+ m_axes[AxisType.kZ.value] = kDefaultZChannel;
+ m_axes[AxisType.kTwist.value] = kDefaultTwistChannel;
+ m_axes[AxisType.kThrottle.value] = kDefaultThrottleChannel;
HAL.report(tResourceType.kResourceType_Joystick, port + 1);
}
@@ -106,7 +73,7 @@
* @param channel The channel to set the axis to.
*/
public void setXChannel(int channel) {
- m_axes[Axis.kX.value] = (byte) channel;
+ m_axes[AxisType.kX.value] = (byte) channel;
}
/**
@@ -115,7 +82,7 @@
* @param channel The channel to set the axis to.
*/
public void setYChannel(int channel) {
- m_axes[Axis.kY.value] = (byte) channel;
+ m_axes[AxisType.kY.value] = (byte) channel;
}
/**
@@ -124,7 +91,7 @@
* @param channel The channel to set the axis to.
*/
public void setZChannel(int channel) {
- m_axes[Axis.kZ.value] = (byte) channel;
+ m_axes[AxisType.kZ.value] = (byte) channel;
}
/**
@@ -133,7 +100,7 @@
* @param channel The channel to set the axis to.
*/
public void setThrottleChannel(int channel) {
- m_axes[Axis.kThrottle.value] = (byte) channel;
+ m_axes[AxisType.kThrottle.value] = (byte) channel;
}
/**
@@ -142,7 +109,7 @@
* @param channel The channel to set the axis to.
*/
public void setTwistChannel(int channel) {
- m_axes[Axis.kTwist.value] = (byte) channel;
+ m_axes[AxisType.kTwist.value] = (byte) channel;
}
/**
@@ -151,7 +118,7 @@
* @return The channel for the axis.
*/
public int getXChannel() {
- return m_axes[Axis.kX.value];
+ return m_axes[AxisType.kX.value];
}
/**
@@ -160,7 +127,7 @@
* @return The channel for the axis.
*/
public int getYChannel() {
- return m_axes[Axis.kY.value];
+ return m_axes[AxisType.kY.value];
}
/**
@@ -169,7 +136,7 @@
* @return The channel for the axis.
*/
public int getZChannel() {
- return m_axes[Axis.kZ.value];
+ return m_axes[AxisType.kZ.value];
}
/**
@@ -178,7 +145,7 @@
* @return The channel for the axis.
*/
public int getTwistChannel() {
- return m_axes[Axis.kTwist.value];
+ return m_axes[AxisType.kTwist.value];
}
/**
@@ -187,31 +154,27 @@
* @return The channel for the axis.
*/
public int getThrottleChannel() {
- return m_axes[Axis.kThrottle.value];
+ return m_axes[AxisType.kThrottle.value];
}
/**
* Get the X value of the joystick. This depends on the mapping of the joystick connected to the
* current port.
*
- * @param hand Unused
* @return The X value of the joystick.
*/
- @Override
- public final double getX(Hand hand) {
- return getRawAxis(m_axes[Axis.kX.value]);
+ public final double getX() {
+ return getRawAxis(m_axes[AxisType.kX.value]);
}
/**
* Get the Y value of the joystick. This depends on the mapping of the joystick connected to the
* current port.
*
- * @param hand Unused
* @return The Y value of the joystick.
*/
- @Override
- public final double getY(Hand hand) {
- return getRawAxis(m_axes[Axis.kY.value]);
+ public final double getY() {
+ return getRawAxis(m_axes[AxisType.kY.value]);
}
/**
@@ -220,7 +183,7 @@
* @return the z position
*/
public double getZ() {
- return getRawAxis(m_axes[Axis.kZ.value]);
+ return getRawAxis(m_axes[AxisType.kZ.value]);
}
/**
@@ -230,7 +193,7 @@
* @return The Twist value of the joystick.
*/
public double getTwist() {
- return getRawAxis(m_axes[Axis.kTwist.value]);
+ return getRawAxis(m_axes[AxisType.kTwist.value]);
}
/**
@@ -240,7 +203,7 @@
* @return The Throttle value of the joystick.
*/
public double getThrottle() {
- return getRawAxis(m_axes[Axis.kThrottle.value]);
+ return getRawAxis(m_axes[AxisType.kThrottle.value]);
}
/**
@@ -249,7 +212,7 @@
* @return The state of the trigger.
*/
public boolean getTrigger() {
- return getRawButton(Button.kTrigger.value);
+ return getRawButton(ButtonType.kTrigger.value);
}
/**
@@ -258,7 +221,7 @@
* @return Whether the button was pressed since the last check.
*/
public boolean getTriggerPressed() {
- return getRawButtonPressed(Button.kTrigger.value);
+ return getRawButtonPressed(ButtonType.kTrigger.value);
}
/**
@@ -267,7 +230,7 @@
* @return Whether the button was released since the last check.
*/
public boolean getTriggerReleased() {
- return getRawButtonReleased(Button.kTrigger.value);
+ return getRawButtonReleased(ButtonType.kTrigger.value);
}
/**
@@ -276,7 +239,7 @@
* @return The state of the top button.
*/
public boolean getTop() {
- return getRawButton(Button.kTop.value);
+ return getRawButton(ButtonType.kTop.value);
}
/**
@@ -285,7 +248,7 @@
* @return Whether the button was pressed since the last check.
*/
public boolean getTopPressed() {
- return getRawButtonPressed(Button.kTop.value);
+ return getRawButtonPressed(ButtonType.kTop.value);
}
/**
@@ -294,7 +257,7 @@
* @return Whether the button was released since the last check.
*/
public boolean getTopReleased() {
- return getRawButtonReleased(Button.kTop.value);
+ return getRawButtonReleased(ButtonType.kTop.value);
}
/**
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafety.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafety.java
index 5dd3a4f..4e76936 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafety.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/MotorSafety.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -11,8 +8,8 @@
import java.util.Set;
/**
- * This base class runs a watchdog timer and calls the subclass's StopMotor()
- * function if the timeout expires.
+ * This base class runs a watchdog timer and calls the subclass's StopMotor() function if the
+ * timeout expires.
*
* <p>The subclass should call feed() whenever the motor value is updated.
*/
@@ -26,9 +23,7 @@
private static final Set<MotorSafety> m_instanceList = new LinkedHashSet<>();
private static final Object m_listMutex = new Object();
- /**
- * MotorSafety constructor.
- */
+ /** MotorSafety constructor. */
public MotorSafety() {
synchronized (m_listMutex) {
m_instanceList.add(this);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Notifier.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Notifier.java
index 546da5b..40384ba 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Notifier.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Notifier.java
@@ -1,18 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReentrantLock;
+import static java.util.Objects.requireNonNull;
import edu.wpi.first.hal.NotifierJNI;
-
-import static java.util.Objects.requireNonNull;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
public class Notifier implements AutoCloseable {
// The thread waiting on the HAL alarm.
@@ -22,9 +18,9 @@
// The C pointer to the notifier object. We don't use it directly, it is
// just passed to the JNI bindings.
private final AtomicInteger m_notifier = new AtomicInteger();
- // The time, in microseconds, at which the corresponding handler should be
- // called. Has the same zero as Utility.getFPGATime().
- private double m_expirationTime;
+ // The time, in seconds, at which the corresponding handler should be
+ // called. Has the same zero as RobotController.getFPGATime().
+ private double m_expirationTimeSeconds;
// The handler passed in by the user which should be called at the
// appropriate interval.
private Runnable m_handler;
@@ -32,7 +28,7 @@
private boolean m_periodic;
// If periodic, the period of the calling; if just once, stores how long it
// is until we call the handler.
- private double m_period;
+ private double m_periodSeconds;
@Override
@SuppressWarnings("NoFinalizer")
@@ -63,28 +59,26 @@
/**
* Update the alarm hardware to reflect the next alarm.
*
- * @param triggerTime the time at which the next alarm will be triggered
+ * @param triggerTimeMicroS the time in microseconds at which the next alarm will be triggered
*/
- private void updateAlarm(long triggerTime) {
+ private void updateAlarm(long triggerTimeMicroS) {
int notifier = m_notifier.get();
if (notifier == 0) {
return;
}
- NotifierJNI.updateNotifierAlarm(notifier, triggerTime);
+ NotifierJNI.updateNotifierAlarm(notifier, triggerTimeMicroS);
}
- /**
- * Update the alarm hardware to reflect the next alarm.
- */
+ /** Update the alarm hardware to reflect the next alarm. */
private void updateAlarm() {
- updateAlarm((long) (m_expirationTime * 1e6));
+ updateAlarm((long) (m_expirationTimeSeconds * 1e6));
}
/**
* Create a Notifier for timer event notification.
*
- * @param run The handler that is called at the notification time which is set
- * using StartSingle or StartPeriodic.
+ * @param run The handler that is called at the notification time which is set using StartSingle
+ * or StartPeriodic.
*/
public Notifier(Runnable run) {
requireNonNull(run);
@@ -92,54 +86,59 @@
m_handler = run;
m_notifier.set(NotifierJNI.initializeNotifier());
- m_thread = new Thread(() -> {
- while (!Thread.interrupted()) {
- int notifier = m_notifier.get();
- if (notifier == 0) {
- break;
- }
- long curTime = NotifierJNI.waitForNotifierAlarm(notifier);
- if (curTime == 0) {
- break;
- }
+ m_thread =
+ new Thread(
+ () -> {
+ while (!Thread.interrupted()) {
+ int notifier = m_notifier.get();
+ if (notifier == 0) {
+ break;
+ }
+ long curTime = NotifierJNI.waitForNotifierAlarm(notifier);
+ if (curTime == 0) {
+ break;
+ }
- Runnable handler = null;
- m_processLock.lock();
- try {
- handler = m_handler;
- if (m_periodic) {
- m_expirationTime += m_period;
- updateAlarm();
- } else {
- // need to update the alarm to cause it to wait again
- updateAlarm((long) -1);
- }
- } finally {
- m_processLock.unlock();
- }
+ Runnable handler = null;
+ m_processLock.lock();
+ try {
+ handler = m_handler;
+ if (m_periodic) {
+ m_expirationTimeSeconds += m_periodSeconds;
+ updateAlarm();
+ } else {
+ // need to update the alarm to cause it to wait again
+ updateAlarm((long) -1);
+ }
+ } finally {
+ m_processLock.unlock();
+ }
- if (handler != null) {
- handler.run();
- }
- }
- });
+ if (handler != null) {
+ handler.run();
+ }
+ }
+ });
m_thread.setName("Notifier");
m_thread.setDaemon(true);
- m_thread.setUncaughtExceptionHandler((thread, error) -> {
- Throwable cause = error.getCause();
- if (cause != null) {
- error = cause;
- }
- DriverStation.reportError("Unhandled exception: " + error.toString(), error.getStackTrace());
- DriverStation.reportError(
- "The loopFunc() method (or methods called by it) should have handled "
- + "the exception above.", false);
- });
+ m_thread.setUncaughtExceptionHandler(
+ (thread, error) -> {
+ Throwable cause = error.getCause();
+ if (cause != null) {
+ error = cause;
+ }
+ DriverStation.reportError(
+ "Unhandled exception: " + error.toString(), error.getStackTrace());
+ DriverStation.reportError(
+ "The loopFunc() method (or methods called by it) should have handled "
+ + "the exception above.",
+ false);
+ });
m_thread.start();
}
/**
- * Sets the name of the notifier. Used for debugging purposes only.
+ * Sets the name of the notifier. Used for debugging purposes only.
*
* @param name Name
*/
@@ -163,17 +162,17 @@
}
/**
- * Register for single event notification. A timer event is queued for a single
- * event after the specified delay.
+ * Register for single event notification. A timer event is queued for a single event after the
+ * specified delay.
*
- * @param delay Seconds to wait before the handler is called.
+ * @param delaySeconds Seconds to wait before the handler is called.
*/
- public void startSingle(double delay) {
+ public void startSingle(double delaySeconds) {
m_processLock.lock();
try {
m_periodic = false;
- m_period = delay;
- m_expirationTime = RobotController.getFPGATime() * 1e-6 + delay;
+ m_periodSeconds = delaySeconds;
+ m_expirationTimeSeconds = RobotController.getFPGATime() * 1e-6 + delaySeconds;
updateAlarm();
} finally {
m_processLock.unlock();
@@ -181,19 +180,19 @@
}
/**
- * Register for periodic event notification. A timer event is queued for
- * periodic event notification. Each time the interrupt occurs, the event will
- * be immediately requeued for the same time interval.
+ * Register for periodic event notification. A timer event is queued for periodic event
+ * notification. Each time the interrupt occurs, the event will be immediately requeued for the
+ * same time interval.
*
- * @param period Period in seconds to call the handler starting one period after
- * the call to this method.
+ * @param periodSeconds Period in seconds to call the handler starting one period after the call
+ * to this method.
*/
- public void startPeriodic(double period) {
+ public void startPeriodic(double periodSeconds) {
m_processLock.lock();
try {
m_periodic = true;
- m_period = period;
- m_expirationTime = RobotController.getFPGATime() * 1e-6 + period;
+ m_periodSeconds = periodSeconds;
+ m_expirationTimeSeconds = RobotController.getFPGATime() * 1e-6 + periodSeconds;
updateAlarm();
} finally {
m_processLock.unlock();
@@ -201,10 +200,9 @@
}
/**
- * Stop timer events from occurring. Stop any repeating timer events from
- * occurring. This will also remove any single notification events from the
- * queue. If a timer-based call to the registered handler is in progress, this
- * function will block until the handler call is complete.
+ * Stop timer events from occurring. Stop any repeating timer events from occurring. This will
+ * also remove any single notification events from the queue. If a timer-based call to the
+ * registered handler is in progress, this function will block until the handler call is complete.
*/
public void stop() {
m_processLock.lock();
@@ -215,4 +213,21 @@
m_processLock.unlock();
}
}
+
+ /**
+ * Sets the HAL notifier thread priority.
+ *
+ * <p>The HAL notifier thread is responsible for managing the FPGA's notifier interrupt and waking
+ * up user's Notifiers when it's their time to run. Giving the HAL notifier thread real-time
+ * priority helps ensure the user's real-time Notifiers, if any, are notified to run in a timely
+ * manner.
+ *
+ * @param realTime Set to true to set a real-time priority, false for standard priority.
+ * @param priority Priority to set the thread to. For real-time, this is 1-99 with 99 being
+ * highest. For non-real-time, this is forced to 0. See "man 7 sched" for more details.
+ * @return True on success.
+ */
+ public static boolean setHALThreadPriority(boolean realTime, int priority) {
+ return NotifierJNI.setHALThreadPriority(realTime, priority);
+ }
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDBase.java
deleted file mode 100644
index 40eb42f..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDBase.java
+++ /dev/null
@@ -1,829 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import java.util.concurrent.locks.ReentrantLock;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.hal.util.BoundaryException;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
-
-/**
- * Class implements a PID Control Loop.
- *
- * <p>Creates a separate thread which reads the given PIDSource and takes care of the integral
- * calculations, as well as writing the given PIDOutput.
- *
- * <p>This feedback controller runs in discrete time, so time deltas are not used in the integral
- * and derivative calculations. Therefore, the sample rate affects the controller's behavior for a
- * given set of PID constants.
- *
- * @deprecated All APIs which use this have been deprecated.
- */
-@Deprecated(since = "2020", forRemoval = true)
-@SuppressWarnings("PMD.TooManyFields")
-public class PIDBase implements PIDInterface, PIDOutput, Sendable, AutoCloseable {
- public static final double kDefaultPeriod = 0.05;
- private static int instances;
-
- // Factor for "proportional" control
- @SuppressWarnings("MemberName")
- private double m_P;
-
- // Factor for "integral" control
- @SuppressWarnings("MemberName")
- private double m_I;
-
- // Factor for "derivative" control
- @SuppressWarnings("MemberName")
- private double m_D;
-
- // Factor for "feed forward" control
- @SuppressWarnings("MemberName")
- private double m_F;
-
- // |maximum output|
- private double m_maximumOutput = 1.0;
-
- // |minimum output|
- private double m_minimumOutput = -1.0;
-
- // Maximum input - limit setpoint to this
- private double m_maximumInput;
-
- // Minimum input - limit setpoint to this
- private double m_minimumInput;
-
- // Input range - difference between maximum and minimum
- private double m_inputRange;
-
- // Do the endpoints wrap around? (e.g., absolute encoder)
- private boolean m_continuous;
-
- // Is the PID controller enabled
- protected boolean m_enabled;
-
- // The prior error (used to compute velocity)
- private double m_prevError;
-
- // The sum of the errors for use in the integral calc
- private double m_totalError;
-
- // The tolerance object used to check if on target
- private Tolerance m_tolerance;
-
- private double m_setpoint;
- private double m_prevSetpoint;
- @SuppressWarnings("PMD.UnusedPrivateField")
- private double m_error;
- private double m_result;
-
- private LinearFilter m_filter;
-
- protected ReentrantLock m_thisMutex = new ReentrantLock();
-
- // Ensures when disable() is called, pidWrite() won't run if calculate()
- // is already running at that time.
- protected ReentrantLock m_pidWriteMutex = new ReentrantLock();
-
- protected PIDSource m_pidInput;
- protected PIDOutput m_pidOutput;
- protected Timer m_setpointTimer;
-
- /**
- * Tolerance is the type of tolerance used to specify if the PID controller is on target.
- *
- * <p>The various implementations of this class such as PercentageTolerance and AbsoluteTolerance
- * specify types of tolerance specifications to use.
- */
- public interface Tolerance {
- boolean onTarget();
- }
-
- /**
- * Used internally for when Tolerance hasn't been set.
- */
- public static class NullTolerance implements Tolerance {
- @Override
- public boolean onTarget() {
- throw new IllegalStateException("No tolerance value set when calling onTarget().");
- }
- }
-
- public class PercentageTolerance implements Tolerance {
- private final double m_percentage;
-
- PercentageTolerance(double value) {
- m_percentage = value;
- }
-
- @Override
- public boolean onTarget() {
- return Math.abs(getError()) < m_percentage / 100 * m_inputRange;
- }
- }
-
- public class AbsoluteTolerance implements Tolerance {
- private final double m_value;
-
- AbsoluteTolerance(double value) {
- m_value = value;
- }
-
- @Override
- public boolean onTarget() {
- return Math.abs(getError()) < m_value;
- }
- }
-
- /**
- * Allocate a PID object with the given constants for P, I, D, and F.
- *
- * @param Kp the proportional coefficient
- * @param Ki the integral coefficient
- * @param Kd the derivative coefficient
- * @param Kf the feed forward term
- * @param source The PIDSource object that is used to get values
- * @param output The PIDOutput object that is set to the output percentage
- */
- @SuppressWarnings("ParameterName")
- public PIDBase(double Kp, double Ki, double Kd, double Kf, PIDSource source,
- PIDOutput output) {
- requireNonNullParam(source, "PIDSource", "PIDBase");
- requireNonNullParam(output, "output", "PIDBase");
-
- m_setpointTimer = new Timer();
- m_setpointTimer.start();
-
- m_P = Kp;
- m_I = Ki;
- m_D = Kd;
- m_F = Kf;
-
- m_pidInput = source;
- m_filter = LinearFilter.movingAverage(1);
-
- m_pidOutput = output;
-
- instances++;
- HAL.report(tResourceType.kResourceType_PIDController, instances);
- m_tolerance = new NullTolerance();
- SendableRegistry.add(this, "PIDController", instances);
- }
-
- /**
- * Allocate a PID object with the given constants for P, I, and D.
- *
- * @param Kp the proportional coefficient
- * @param Ki the integral coefficient
- * @param Kd the derivative coefficient
- * @param source the PIDSource object that is used to get values
- * @param output the PIDOutput object that is set to the output percentage
- */
- @SuppressWarnings("ParameterName")
- public PIDBase(double Kp, double Ki, double Kd, PIDSource source, PIDOutput output) {
- this(Kp, Ki, Kd, 0.0, source, output);
- }
-
- @Override
- public void close() {
- SendableRegistry.remove(this);
- }
-
- /**
- * Read the input, calculate the output accordingly, and write to the output. This should only be
- * called by the PIDTask and is created during initialization.
- */
- @SuppressWarnings({"LocalVariableName", "PMD.ExcessiveMethodLength", "PMD.NPathComplexity"})
- protected void calculate() {
- if (m_pidInput == null || m_pidOutput == null) {
- return;
- }
-
- boolean enabled;
-
- m_thisMutex.lock();
- try {
- enabled = m_enabled;
- } finally {
- m_thisMutex.unlock();
- }
-
- if (enabled) {
- double input;
-
- // Storage for function inputs
- PIDSourceType pidSourceType;
- double P;
- double I;
- double D;
- double feedForward = calculateFeedForward();
- double minimumOutput;
- double maximumOutput;
-
- // Storage for function input-outputs
- double prevError;
- double error;
- double totalError;
-
- m_thisMutex.lock();
- try {
- input = m_filter.calculate(m_pidInput.pidGet());
-
- pidSourceType = m_pidInput.getPIDSourceType();
- P = m_P;
- I = m_I;
- D = m_D;
- minimumOutput = m_minimumOutput;
- maximumOutput = m_maximumOutput;
-
- prevError = m_prevError;
- error = getContinuousError(m_setpoint - input);
- totalError = m_totalError;
- } finally {
- m_thisMutex.unlock();
- }
-
- // Storage for function outputs
- double result;
-
- if (pidSourceType.equals(PIDSourceType.kRate)) {
- if (P != 0) {
- totalError = clamp(totalError + error, minimumOutput / P,
- maximumOutput / P);
- }
-
- result = P * totalError + D * error + feedForward;
- } else {
- if (I != 0) {
- totalError = clamp(totalError + error, minimumOutput / I,
- maximumOutput / I);
- }
-
- result = P * error + I * totalError + D * (error - prevError)
- + feedForward;
- }
-
- result = clamp(result, minimumOutput, maximumOutput);
-
- // Ensures m_enabled check and pidWrite() call occur atomically
- m_pidWriteMutex.lock();
- try {
- m_thisMutex.lock();
- try {
- if (m_enabled) {
- // Don't block other PIDController operations on pidWrite()
- m_thisMutex.unlock();
-
- m_pidOutput.pidWrite(result);
- }
- } finally {
- if (m_thisMutex.isHeldByCurrentThread()) {
- m_thisMutex.unlock();
- }
- }
- } finally {
- m_pidWriteMutex.unlock();
- }
-
- m_thisMutex.lock();
- try {
- m_prevError = error;
- m_error = error;
- m_totalError = totalError;
- m_result = result;
- } finally {
- m_thisMutex.unlock();
- }
- }
- }
-
- /**
- * Calculate the feed forward term.
- *
- * <p>Both of the provided feed forward calculations are velocity feed forwards. If a different
- * feed forward calculation is desired, the user can override this function and provide his or
- * her own. This function does no synchronization because the PIDController class only calls it
- * in synchronized code, so be careful if calling it oneself.
- *
- * <p>If a velocity PID controller is being used, the F term should be set to 1 over the maximum
- * setpoint for the output. If a position PID controller is being used, the F term should be set
- * to 1 over the maximum speed for the output measured in setpoint units per this controller's
- * update period (see the default period in this class's constructor).
- */
- protected double calculateFeedForward() {
- if (m_pidInput.getPIDSourceType().equals(PIDSourceType.kRate)) {
- return m_F * getSetpoint();
- } else {
- double temp = m_F * getDeltaSetpoint();
- m_prevSetpoint = m_setpoint;
- m_setpointTimer.reset();
- return temp;
- }
- }
-
- /**
- * Set the PID Controller gain parameters. Set the proportional, integral, and differential
- * coefficients.
- *
- * @param p Proportional coefficient
- * @param i Integral coefficient
- * @param d Differential coefficient
- */
- @Override
- @SuppressWarnings("ParameterName")
- public void setPID(double p, double i, double d) {
- m_thisMutex.lock();
- try {
- m_P = p;
- m_I = i;
- m_D = d;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the PID Controller gain parameters. Set the proportional, integral, and differential
- * coefficients.
- *
- * @param p Proportional coefficient
- * @param i Integral coefficient
- * @param d Differential coefficient
- * @param f Feed forward coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setPID(double p, double i, double d, double f) {
- m_thisMutex.lock();
- try {
- m_P = p;
- m_I = i;
- m_D = d;
- m_F = f;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the Proportional coefficient of the PID controller gain.
- *
- * @param p Proportional coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setP(double p) {
- m_thisMutex.lock();
- try {
- m_P = p;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the Integral coefficient of the PID controller gain.
- *
- * @param i Integral coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setI(double i) {
- m_thisMutex.lock();
- try {
- m_I = i;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the Differential coefficient of the PID controller gain.
- *
- * @param d differential coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setD(double d) {
- m_thisMutex.lock();
- try {
- m_D = d;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the Feed forward coefficient of the PID controller gain.
- *
- * @param f feed forward coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setF(double f) {
- m_thisMutex.lock();
- try {
- m_F = f;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Get the Proportional coefficient.
- *
- * @return proportional coefficient
- */
- @Override
- public double getP() {
- m_thisMutex.lock();
- try {
- return m_P;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Get the Integral coefficient.
- *
- * @return integral coefficient
- */
- @Override
- public double getI() {
- m_thisMutex.lock();
- try {
- return m_I;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Get the Differential coefficient.
- *
- * @return differential coefficient
- */
- @Override
- public double getD() {
- m_thisMutex.lock();
- try {
- return m_D;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Get the Feed forward coefficient.
- *
- * @return feed forward coefficient
- */
- public double getF() {
- m_thisMutex.lock();
- try {
- return m_F;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Return the current PID result This is always centered on zero and constrained the the max and
- * min outs.
- *
- * @return the latest calculated output
- */
- public double get() {
- m_thisMutex.lock();
- try {
- return m_result;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the PID controller to consider the input to be continuous, Rather then using the max and
- * min input range as constraints, it considers them to be the same point and automatically
- * calculates the shortest route to the setpoint.
- *
- * @param continuous Set to true turns on continuous, false turns off continuous
- */
- public void setContinuous(boolean continuous) {
- if (continuous && m_inputRange <= 0) {
- throw new IllegalStateException("No input range set when calling setContinuous().");
- }
- m_thisMutex.lock();
- try {
- m_continuous = continuous;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the PID controller to consider the input to be continuous, Rather then using the max and
- * min input range as constraints, it considers them to be the same point and automatically
- * calculates the shortest route to the setpoint.
- */
- public void setContinuous() {
- setContinuous(true);
- }
-
- /**
- * Sets the maximum and minimum values expected from the input and setpoint.
- *
- * @param minimumInput the minimum value expected from the input
- * @param maximumInput the maximum value expected from the input
- */
- public void setInputRange(double minimumInput, double maximumInput) {
- m_thisMutex.lock();
- try {
- if (minimumInput > maximumInput) {
- throw new BoundaryException("Lower bound is greater than upper bound");
- }
- m_minimumInput = minimumInput;
- m_maximumInput = maximumInput;
- m_inputRange = maximumInput - minimumInput;
- } finally {
- m_thisMutex.unlock();
- }
-
- setSetpoint(m_setpoint);
- }
-
- /**
- * Sets the minimum and maximum values to write.
- *
- * @param minimumOutput the minimum percentage to write to the output
- * @param maximumOutput the maximum percentage to write to the output
- */
- public void setOutputRange(double minimumOutput, double maximumOutput) {
- m_thisMutex.lock();
- try {
- if (minimumOutput > maximumOutput) {
- throw new BoundaryException("Lower bound is greater than upper bound");
- }
- m_minimumOutput = minimumOutput;
- m_maximumOutput = maximumOutput;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the setpoint for the PIDController.
- *
- * @param setpoint the desired setpoint
- */
- @Override
- public void setSetpoint(double setpoint) {
- m_thisMutex.lock();
- try {
- if (m_maximumInput > m_minimumInput) {
- if (setpoint > m_maximumInput) {
- m_setpoint = m_maximumInput;
- } else if (setpoint < m_minimumInput) {
- m_setpoint = m_minimumInput;
- } else {
- m_setpoint = setpoint;
- }
- } else {
- m_setpoint = setpoint;
- }
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Returns the current setpoint of the PIDController.
- *
- * @return the current setpoint
- */
- @Override
- public double getSetpoint() {
- m_thisMutex.lock();
- try {
- return m_setpoint;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Returns the change in setpoint over time of the PIDController.
- *
- * @return the change in setpoint over time
- */
- public double getDeltaSetpoint() {
- m_thisMutex.lock();
- try {
- return (m_setpoint - m_prevSetpoint) / m_setpointTimer.get();
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Returns the current difference of the input from the setpoint.
- *
- * @return the current error
- */
- @Override
- public double getError() {
- m_thisMutex.lock();
- try {
- return getContinuousError(getSetpoint() - m_filter.calculate(m_pidInput.pidGet()));
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Returns the current difference of the error over the past few iterations. You can specify the
- * number of iterations to average with setToleranceBuffer() (defaults to 1). getAvgError() is
- * used for the onTarget() function.
- *
- * @deprecated Use getError(), which is now already filtered.
- * @return the current average of the error
- */
- @Deprecated
- public double getAvgError() {
- m_thisMutex.lock();
- try {
- return getError();
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Sets what type of input the PID controller will use.
- *
- * @param pidSource the type of input
- */
- public void setPIDSourceType(PIDSourceType pidSource) {
- m_pidInput.setPIDSourceType(pidSource);
- }
-
- /**
- * Returns the type of input the PID controller is using.
- *
- * @return the PID controller input type
- */
- public PIDSourceType getPIDSourceType() {
- return m_pidInput.getPIDSourceType();
- }
-
- /**
- * Set the PID tolerance using a Tolerance object. Tolerance can be specified as a percentage of
- * the range or as an absolute value. The Tolerance object encapsulates those options in an
- * object. Use it by creating the type of tolerance that you want to use: setTolerance(new
- * PIDController.AbsoluteTolerance(0.1))
- *
- * @deprecated Use setPercentTolerance() instead.
- * @param tolerance A tolerance object of the right type, e.g. PercentTolerance or
- * AbsoluteTolerance
- */
- @Deprecated
- public void setTolerance(Tolerance tolerance) {
- m_tolerance = tolerance;
- }
-
- /**
- * Set the absolute error which is considered tolerable for use with OnTarget.
- *
- * @param absvalue absolute error which is tolerable in the units of the input object
- */
- public void setAbsoluteTolerance(double absvalue) {
- m_thisMutex.lock();
- try {
- m_tolerance = new AbsoluteTolerance(absvalue);
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the percentage error which is considered tolerable for use with OnTarget. (Input of 15.0 =
- * 15 percent)
- *
- * @param percentage percent error which is tolerable
- */
- public void setPercentTolerance(double percentage) {
- m_thisMutex.lock();
- try {
- m_tolerance = new PercentageTolerance(percentage);
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Set the number of previous error samples to average for tolerancing. When determining whether a
- * mechanism is on target, the user may want to use a rolling average of previous measurements
- * instead of a precise position or velocity. This is useful for noisy sensors which return a few
- * erroneous measurements when the mechanism is on target. However, the mechanism will not
- * register as on target for at least the specified bufLength cycles.
- *
- * @deprecated Use a LinearFilter as the input.
- * @param bufLength Number of previous cycles to average.
- */
- @Deprecated
- public void setToleranceBuffer(int bufLength) {
- m_thisMutex.lock();
- try {
- m_filter = LinearFilter.movingAverage(bufLength);
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Return true if the error is within the percentage of the total input range, determined by
- * setTolerance. This assumes that the maximum and minimum input were set using setInput.
- *
- * @return true if the error is less than the tolerance
- */
- public boolean onTarget() {
- m_thisMutex.lock();
- try {
- return m_tolerance.onTarget();
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Reset the previous error, the integral term, and disable the controller.
- */
- @Override
- public void reset() {
- m_thisMutex.lock();
- try {
- m_prevError = 0;
- m_totalError = 0;
- m_result = 0;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Passes the output directly to setSetpoint().
- *
- * <p>PIDControllers can be nested by passing a PIDController as another PIDController's output.
- * In that case, the output of the parent controller becomes the input (i.e., the reference) of
- * the child.
- *
- * <p>It is the caller's responsibility to put the data into a valid form for setSetpoint().
- */
- @Override
- public void pidWrite(double output) {
- setSetpoint(output);
- }
-
- @Override
- public void initSendable(SendableBuilder builder) {
- builder.setSmartDashboardType("PIDController");
- builder.setSafeState(this::reset);
- builder.addDoubleProperty("p", this::getP, this::setP);
- builder.addDoubleProperty("i", this::getI, this::setI);
- builder.addDoubleProperty("d", this::getD, this::setD);
- builder.addDoubleProperty("f", this::getF, this::setF);
- builder.addDoubleProperty("setpoint", this::getSetpoint, this::setSetpoint);
- }
-
- /**
- * Wraps error around for continuous inputs. The original error is returned if continuous mode is
- * disabled. This is an unsynchronized function.
- *
- * @param error The current error of the PID controller.
- * @return Error for continuous inputs.
- */
- protected double getContinuousError(double error) {
- if (m_continuous && m_inputRange > 0) {
- error %= m_inputRange;
- if (Math.abs(error) > m_inputRange / 2) {
- if (error > 0) {
- return error - m_inputRange;
- } else {
- return error + m_inputRange;
- }
- }
- }
-
- return error;
- }
-
- private static double clamp(double value, double low, double high) {
- return Math.max(low, Math.min(value, high));
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDController.java
deleted file mode 100644
index 881723e..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDController.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-
-/**
- * Class implements a PID Control Loop.
- *
- * <p>Creates a separate thread which reads the given PIDSource and takes care of the integral
- * calculations, as well as writing the given PIDOutput.
- *
- * <p>This feedback controller runs in discrete time, so time deltas are not used in the integral
- * and derivative calculations. Therefore, the sample rate affects the controller's behavior for a
- * given set of PID constants.
- *
- * @deprecated Use {@link edu.wpi.first.wpilibj.controller.PIDController} instead.
- */
-@Deprecated(since = "2020", forRemoval = true)
-public class PIDController extends PIDBase implements Controller, AutoCloseable {
- Notifier m_controlLoop = new Notifier(this::calculate);
-
- /**
- * Allocate a PID object with the given constants for P, I, D, and F.
- *
- * @param Kp the proportional coefficient
- * @param Ki the integral coefficient
- * @param Kd the derivative coefficient
- * @param Kf the feed forward term
- * @param source The PIDSource object that is used to get values
- * @param output The PIDOutput object that is set to the output percentage
- * @param period the loop time for doing calculations in seconds.
- * This particularly affects calculations of
- * the integral and differential terms.
- * The default is 0.05 (50ms).
- */
- @SuppressWarnings("ParameterName")
- public PIDController(double Kp, double Ki, double Kd, double Kf, PIDSource source,
- PIDOutput output, double period) {
- super(Kp, Ki, Kd, Kf, source, output);
- m_controlLoop.startPeriodic(period);
- }
-
- /**
- * Allocate a PID object with the given constants for P, I, D and period.
- *
- * @param Kp the proportional coefficient
- * @param Ki the integral coefficient
- * @param Kd the derivative coefficient
- * @param source the PIDSource object that is used to get values
- * @param output the PIDOutput object that is set to the output percentage
- * @param period the loop time for doing calculations in seconds.
- * This particularly affects calculations of
- * the integral and differential terms.
- * The default is 0.05 (50ms).
- */
- @SuppressWarnings("ParameterName")
- public PIDController(double Kp, double Ki, double Kd, PIDSource source, PIDOutput output,
- double period) {
- this(Kp, Ki, Kd, 0.0, source, output, period);
- }
-
- /**
- * Allocate a PID object with the given constants for P, I, D, using a 50ms period.
- *
- * @param Kp the proportional coefficient
- * @param Ki the integral coefficient
- * @param Kd the derivative coefficient
- * @param source The PIDSource object that is used to get values
- * @param output The PIDOutput object that is set to the output percentage
- */
- @SuppressWarnings("ParameterName")
- public PIDController(double Kp, double Ki, double Kd, PIDSource source, PIDOutput output) {
- this(Kp, Ki, Kd, source, output, kDefaultPeriod);
- }
-
- /**
- * Allocate a PID object with the given constants for P, I, D, using a 50ms period.
- *
- * @param Kp the proportional coefficient
- * @param Ki the integral coefficient
- * @param Kd the derivative coefficient
- * @param Kf the feed forward term
- * @param source The PIDSource object that is used to get values
- * @param output The PIDOutput object that is set to the output percentage
- */
- @SuppressWarnings("ParameterName")
- public PIDController(double Kp, double Ki, double Kd, double Kf, PIDSource source,
- PIDOutput output) {
- this(Kp, Ki, Kd, Kf, source, output, kDefaultPeriod);
- }
-
- @Override
- public void close() {
- m_controlLoop.close();
- m_thisMutex.lock();
- try {
- m_pidOutput = null;
- m_pidInput = null;
- m_controlLoop = null;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Begin running the PIDController.
- */
- @Override
- public void enable() {
- m_thisMutex.lock();
- try {
- m_enabled = true;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Stop running the PIDController, this sets the output to zero before stopping.
- */
- @Override
- public void disable() {
- // Ensures m_enabled check and pidWrite() call occur atomically
- m_pidWriteMutex.lock();
- try {
- m_thisMutex.lock();
- try {
- m_enabled = false;
- } finally {
- m_thisMutex.unlock();
- }
-
- m_pidOutput.pidWrite(0);
- } finally {
- m_pidWriteMutex.unlock();
- }
- }
-
- /**
- * Set the enabled state of the PIDController.
- */
- public void setEnabled(boolean enable) {
- if (enable) {
- enable();
- } else {
- disable();
- }
- }
-
- /**
- * Return true if PIDController is enabled.
- */
- public boolean isEnabled() {
- m_thisMutex.lock();
- try {
- return m_enabled;
- } finally {
- m_thisMutex.unlock();
- }
- }
-
- /**
- * Reset the previous error, the integral term, and disable the controller.
- */
- @Override
- public void reset() {
- disable();
-
- super.reset();
- }
-
- @Override
- public void initSendable(SendableBuilder builder) {
- super.initSendable(builder);
- builder.addBooleanProperty("enabled", this::isEnabled, this::setEnabled);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDInterface.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDInterface.java
deleted file mode 100644
index 10e60d3..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDInterface.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-@Deprecated(since = "2020", forRemoval = true)
-@SuppressWarnings("SummaryJavadoc")
-public interface PIDInterface {
- @SuppressWarnings("ParameterName")
- void setPID(double p, double i, double d);
-
- double getP();
-
- double getI();
-
- double getD();
-
- void setSetpoint(double setpoint);
-
- double getSetpoint();
-
- double getError();
-
- void reset();
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDOutput.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDOutput.java
deleted file mode 100644
index e9af2ff..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDOutput.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-/**
- * This interface allows PIDController to write it's results to its output.
- *
- * @deprecated Use DoubleConsumer and new PIDController class.
- */
-@FunctionalInterface
-@Deprecated(since = "2020", forRemoval = true)
-public interface PIDOutput {
- /**
- * Set the output to the value calculated by PIDController.
- *
- * @param output the value calculated by PIDController
- */
- void pidWrite(double output);
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSource.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSource.java
deleted file mode 100644
index 3c4f1f5..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSource.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-/**
- * This interface allows for PIDController to automatically read from this object.
- *
- * @deprecated Use DoubleSupplier and new PIDController class.
- */
-@Deprecated(since = "2020", forRemoval = true)
-public interface PIDSource {
- /**
- * Set which parameter of the device you are using as a process control variable.
- *
- * @param pidSource An enum to select the parameter.
- */
- void setPIDSourceType(PIDSourceType pidSource);
-
- /**
- * Get which parameter of the device you are using as a process control variable.
- *
- * @return the currently selected PID source parameter
- */
- PIDSourceType getPIDSourceType();
-
- /**
- * Get the result to use in PIDController.
- *
- * @return the result to use in PIDController
- */
- double pidGet();
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSourceType.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSourceType.java
deleted file mode 100644
index 7508be5..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PIDSourceType.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-/**
- * A description for the type of output value to provide to a PIDController.
- */
-@Deprecated(since = "2020", forRemoval = true)
-public enum PIDSourceType {
- kDisplacement,
- kRate
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PS4Controller.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PS4Controller.java
new file mode 100644
index 0000000..e3eb052
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PS4Controller.java
@@ -0,0 +1,535 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+
+/**
+ * Handle input from PS4 controllers connected to the Driver Station.
+ *
+ * <p>This class handles PS4 input that comes from the Driver Station. Each time a value is
+ * requested the most recent value is returned. There is a single class instance for each controller
+ * and the mapping of ports to hardware buttons depends on the code in the Driver Station.
+ */
+public class PS4Controller extends GenericHID {
+ /**
+ * Construct an instance of a device.
+ *
+ * @param port The port index on the Driver Station that the device is plugged into.
+ */
+ public PS4Controller(int port) {
+ super(port);
+ HAL.report(tResourceType.kResourceType_PS4Controller, port + 1);
+ }
+
+ /** Represents a digital button on a PS4Controller. */
+ public enum Button {
+ kSquare(1),
+ kCross(2),
+ kCircle(3),
+ kTriangle(4),
+ kL1(5),
+ kR1(6),
+ kL2(7),
+ kR2(8),
+ kShare(9),
+ kOptions(10),
+ kL3(11),
+ kR3(12),
+ kPS(13),
+ kTouchpad(14);
+
+ public final int value;
+
+ Button(int index) {
+ this.value = index;
+ }
+
+ /**
+ * Get the human-friendly name of the button, matching the relevant methods. This is done by
+ * stripping the leading `k`, and if not the touchpad append `Button`.
+ *
+ * <p>Primarily used for automated unit tests.
+ *
+ * @return the human-friendly name of the button.
+ */
+ @Override
+ public String toString() {
+ var name = this.name().substring(1); // Remove leading `k`
+ if (this == kTouchpad) {
+ return name;
+ }
+ return name + "Button";
+ }
+ }
+
+ /** Represents an axis on a PS4Controller. */
+ public enum Axis {
+ kLeftX(0),
+ kLeftY(1),
+ kRightX(2),
+ kRightY(5),
+ kL2(3),
+ kR2(4);
+
+ public final int value;
+
+ Axis(int index) {
+ value = index;
+ }
+
+ /**
+ * Get the human-friendly name of the axis, matching the relevant methods. This is done by
+ * stripping the leading `k`, and if one of L2/R2 append `Axis`.
+ *
+ * <p>Primarily used for automated unit tests.
+ *
+ * @return the human-friendly name of the axis.
+ */
+ @Override
+ public String toString() {
+ var name = this.name().substring(1); // Remove leading `k`
+ if (name.endsWith("2")) {
+ return name + "Axis";
+ }
+ return name;
+ }
+ }
+
+ /**
+ * Get the X axis value of left side of the controller.
+ *
+ * @return the axis value.
+ */
+ public double getLeftX() {
+ return getRawAxis(Axis.kLeftX.value);
+ }
+
+ /**
+ * Get the X axis value of right side of the controller.
+ *
+ * @return the axis value.
+ */
+ public double getRightX() {
+ return getRawAxis(Axis.kRightX.value);
+ }
+
+ /**
+ * Get the Y axis value of left side of the controller.
+ *
+ * @return the axis value.
+ */
+ public double getLeftY() {
+ return getRawAxis(Axis.kLeftY.value);
+ }
+
+ /**
+ * Get the Y axis value of right side of the controller.
+ *
+ * @return the axis value.
+ */
+ public double getRightY() {
+ return getRawAxis(Axis.kRightY.value);
+ }
+
+ /**
+ * 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 getRawAxis(Axis.kL2.value);
+ }
+
+ /**
+ * 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 getRawAxis(Axis.kR2.value);
+ }
+
+ /**
+ * Read the value of the left trigger button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getL2Button() {
+ return getRawButton(Button.kL2.value);
+ }
+
+ /**
+ * Read the value of the right trigger button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getR2Button() {
+ return getRawButton(Button.kR2.value);
+ }
+
+ /**
+ * Whether the L2 button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getL2ButtonPressed() {
+ return getRawButtonPressed(Button.kL2.value);
+ }
+
+ /**
+ * Whether the R2 button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getR2ButtonPressed() {
+ return getRawButtonPressed(Button.kR2.value);
+ }
+
+ /**
+ * Whether the L2 button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getL2ButtonReleased() {
+ return getRawButtonReleased(Button.kL2.value);
+ }
+
+ /**
+ * Whether the R2 button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getR2ButtonReleased() {
+ return getRawButtonReleased(Button.kR2.value);
+ }
+
+ /**
+ * Read the value of the L1 button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getL1Button() {
+ return getRawButton(Button.kL1.value);
+ }
+
+ /**
+ * Read the value of the R1 button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getR1Button() {
+ return getRawButton(Button.kR1.value);
+ }
+
+ /**
+ * Whether the L1 button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getL1ButtonPressed() {
+ return getRawButtonPressed(Button.kL1.value);
+ }
+
+ /**
+ * Whether the R1 button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getR1ButtonPressed() {
+ return getRawButtonPressed(Button.kR1.value);
+ }
+
+ /**
+ * Whether the L1 button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getL1ButtonReleased() {
+ return getRawButtonReleased(Button.kL1.value);
+ }
+
+ /**
+ * Whether the R1 button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getR1ButtonReleased() {
+ return getRawButtonReleased(Button.kR1.value);
+ }
+
+ /**
+ * Read the value of the L3 button (pressing the left analog stick) on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getL3Button() {
+ return getRawButton(Button.kL3.value);
+ }
+
+ /**
+ * Read the value of the R3 button (pressing the right analog stick) on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getR3Button() {
+ return getRawButton(Button.kR3.value);
+ }
+
+ /**
+ * Whether the L3 (left stick) button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getL3ButtonPressed() {
+ return getRawButtonPressed(Button.kL3.value);
+ }
+
+ /**
+ * Whether the R3 (right stick) button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getR3ButtonPressed() {
+ return getRawButtonPressed(Button.kR3.value);
+ }
+
+ /**
+ * Whether the L3 (left stick) button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getL3ButtonReleased() {
+ return getRawButtonReleased(Button.kL3.value);
+ }
+
+ /**
+ * Whether the R3 (right stick) button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getR3ButtonReleased() {
+ return getRawButtonReleased(Button.kR3.value);
+ }
+
+ /**
+ * Read the value of the Square button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getSquareButton() {
+ return getRawButton(Button.kSquare.value);
+ }
+
+ /**
+ * Whether the Square button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getSquareButtonPressed() {
+ return getRawButtonPressed(Button.kSquare.value);
+ }
+
+ /**
+ * Whether the Square button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getSquareButtonReleased() {
+ return getRawButtonReleased(Button.kSquare.value);
+ }
+
+ /**
+ * Read the value of the Cross button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getCrossButton() {
+ return getRawButton(Button.kCross.value);
+ }
+
+ /**
+ * Whether the Cross button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getCrossButtonPressed() {
+ return getRawButtonPressed(Button.kCross.value);
+ }
+
+ /**
+ * Whether the Cross button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getCrossButtonReleased() {
+ return getRawButtonReleased(Button.kCross.value);
+ }
+
+ /**
+ * Read the value of the Triangle button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getTriangleButton() {
+ return getRawButton(Button.kTriangle.value);
+ }
+
+ /**
+ * Whether the Triangle button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getTriangleButtonPressed() {
+ return getRawButtonPressed(Button.kTriangle.value);
+ }
+
+ /**
+ * Whether the Triangle button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getTriangleButtonReleased() {
+ return getRawButtonReleased(Button.kTriangle.value);
+ }
+
+ /**
+ * Read the value of the Circle button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getCircleButton() {
+ return getRawButton(Button.kCircle.value);
+ }
+
+ /**
+ * Whether the Circle button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getCircleButtonPressed() {
+ return getRawButtonPressed(Button.kCircle.value);
+ }
+
+ /**
+ * Whether the Circle button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getCircleButtonReleased() {
+ return getRawButtonReleased(Button.kCircle.value);
+ }
+
+ /**
+ * Read the value of the share button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getShareButton() {
+ return getRawButton(Button.kShare.value);
+ }
+
+ /**
+ * Whether the share button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getShareButtonPressed() {
+ return getRawButtonPressed(Button.kShare.value);
+ }
+
+ /**
+ * Whether the share button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getShareButtonReleased() {
+ return getRawButtonReleased(Button.kShare.value);
+ }
+
+ /**
+ * Read the value of the PS button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getPSButton() {
+ return getRawButton(Button.kPS.value);
+ }
+
+ /**
+ * Whether the PS button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getPSButtonPressed() {
+ return getRawButtonPressed(Button.kPS.value);
+ }
+
+ /**
+ * Whether the PS button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getPSButtonReleased() {
+ return getRawButtonReleased(Button.kPS.value);
+ }
+
+ /**
+ * Read the value of the options button on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getOptionsButton() {
+ return getRawButton(Button.kOptions.value);
+ }
+
+ /**
+ * Whether the options button was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getOptionsButtonPressed() {
+ return getRawButtonPressed(Button.kOptions.value);
+ }
+
+ /**
+ * Whether the options button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getOptionsButtonReleased() {
+ return getRawButtonReleased(Button.kOptions.value);
+ }
+
+ /**
+ * Read the value of the touchpad on the controller.
+ *
+ * @return The state of the touchpad.
+ */
+ public boolean getTouchpad() {
+ return getRawButton(Button.kTouchpad.value);
+ }
+
+ /**
+ * Whether the touchpad was pressed since the last check.
+ *
+ * @return Whether the touchpad was pressed since the last check.
+ */
+ public boolean getTouchpadPressed() {
+ return getRawButtonPressed(Button.kTouchpad.value);
+ }
+
+ /**
+ * Whether the touchpad was released since the last check.
+ *
+ * @return Whether the touchpad was released since the last check.
+ */
+ public boolean getTouchpadReleased() {
+ return getRawButtonReleased(Button.kTouchpad.value);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWM.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWM.java
index 8febd2c..9d86ab8 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWM.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWM.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -11,8 +8,9 @@
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.PWMConfigDataResult;
import edu.wpi.first.hal.PWMJNI;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Class implements the PWM generation in the FPGA.
@@ -26,36 +24,42 @@
* center value - 999 to 2 = linear scaling from "center" to "full reverse" - 1 = minimum pulse
* width (currently .5ms) - 0 = disabled (i.e. PWM output is held low)
*/
-public class PWM extends MotorSafety implements Sendable, AutoCloseable {
- /**
- * Represents the amount to multiply the minimum servo-pulse pwm period by.
- */
+public class PWM implements Sendable, AutoCloseable {
+ /** Represents the amount to multiply the minimum servo-pulse pwm period by. */
public enum PeriodMultiplier {
- /**
- * Period Multiplier: don't skip pulses. PWM pulses occur every 5.005 ms
- */
+ /** Period Multiplier: don't skip pulses. PWM pulses occur every 5.005 ms */
k1X,
- /**
- * Period Multiplier: skip every other pulse. PWM pulses occur every 10.010 ms
- */
+ /** Period Multiplier: skip every other pulse. PWM pulses occur every 10.010 ms */
k2X,
- /**
- * Period Multiplier: skip three out of four pulses. PWM pulses occur every 20.020 ms
- */
+ /** Period Multiplier: skip three out of four pulses. PWM pulses occur every 20.020 ms */
k4X
}
private final int m_channel;
- // Package private to use from AddressableLED
- int m_handle;
+ private int m_handle;
+
+ /**
+ * Allocate a PWM given a channel.
+ *
+ * <p>Checks channel value range and allocates the appropriate channel. The allocation is only
+ * done to help users ensure that they don't double assign channels.
+ *
+ * <p>By default, adds itself to SendableRegistry and LiveWindow.
+ *
+ * @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port
+ */
+ public PWM(final int channel) {
+ this(channel, true);
+ }
/**
* Allocate a PWM given a channel.
*
* @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port
+ * @param registerSendable If true, adds this instance to SendableRegistry and LiveWindow
*/
- public PWM(final int channel) {
+ public PWM(final int channel, final boolean registerSendable) {
SensorUtil.checkPWMChannel(channel);
m_channel = channel;
@@ -66,14 +70,12 @@
PWMJNI.setPWMEliminateDeadband(m_handle, false);
HAL.report(tResourceType.kResourceType_PWM, channel + 1);
- SendableRegistry.addLW(this, "PWM", channel);
-
- setSafetyEnabled(false);
+ if (registerSendable) {
+ SendableRegistry.addLW(this, "PWM", channel);
+ }
}
- /**
- * Free the resource associated with the PWM channel and set the value to 0.
- */
+ /** Free the resource associated with the PWM channel and set the value to 0. */
@Override
public void close() {
SendableRegistry.remove(this);
@@ -85,22 +87,12 @@
m_handle = 0;
}
- @Override
- public void stopMotor() {
- setDisabled();
- }
-
- @Override
- public String getDescription() {
- return "PWM " + getChannel();
- }
-
/**
- * Optionally eliminate the deadband from a speed controller.
+ * Optionally eliminate the deadband from a motor controller.
*
- * @param eliminateDeadband If true, set the motor curve on the Jaguar to eliminate the deadband
- * in the middle of the range. Otherwise, keep the full range without
- * modifying any values.
+ * @param eliminateDeadband If true, set the motor curve for the motor controller to eliminate the
+ * deadband in the middle of the range. Otherwise, keep the full range without modifying any
+ * values.
*/
public void enableDeadbandElimination(boolean eliminateDeadband) {
PWMJNI.setPWMEliminateDeadband(m_handle, eliminateDeadband);
@@ -111,21 +103,23 @@
* type of controller. The values determine the upper and lower speeds as well as the deadband
* bracket.
*
- * @param max The max PWM pulse width in ms
+ * @param max The max PWM pulse width in ms
* @param deadbandMax The high end of the deadband range pulse width in ms
- * @param center The center (off) pulse width in ms
+ * @param center The center (off) pulse width in ms
* @param deadbandMin The low end of the deadband pulse width in ms
- * @param min The minimum pulse width in ms
+ * @param min The minimum pulse width in ms
*/
- public void setBounds(double max, double deadbandMax, double center, double deadbandMin,
- double min) {
+ public void setBounds(
+ double max, double deadbandMax, double center, double deadbandMin, double min) {
PWMJNI.setPWMConfig(m_handle, max, deadbandMax, center, deadbandMin, min);
}
/**
- * Gets the bounds on the PWM pulse widths. This Gets the bounds on the PWM values for a
- * particular type of controller. The values determine the upper and lower speeds as well
- * as the deadband bracket.
+ * Gets the bounds on the PWM pulse widths. This gets the bounds on the PWM values for a
+ * particular type of controller. The values determine the upper and lower speeds as well as the
+ * deadband bracket.
+ *
+ * @return The bounds on the PWM pulse widths.
*/
public PWMConfigDataResult getRawBounds() {
return PWMJNI.getPWMConfigRaw(m_handle);
@@ -169,9 +163,9 @@
/**
* Set the PWM value based on a speed.
*
- * <p>This is intended to be used by speed controllers.
+ * <p>This is intended to be used by motor controllers.
*
- * @param speed The speed to set the speed controller between -1.0 and 1.0.
+ * @param speed The speed to set the motor controller between -1.0 and 1.0.
* @pre SetMaxPositivePwm() called.
* @pre SetMinPositivePwm() called.
* @pre SetCenterPwm() called.
@@ -185,7 +179,7 @@
/**
* Get the PWM value in terms of speed.
*
- * <p>This is intended to be used by speed controllers.
+ * <p>This is intended to be used by motor controllers.
*
* @return The most recently set speed between -1.0 and 1.0.
* @pre SetMaxPositivePwm() called.
@@ -219,10 +213,7 @@
return PWMJNI.getPWMRaw(m_handle);
}
- /**
- * Temporarily disables the PWM output. The next set call will reenable
- * the output.
- */
+ /** Temporarily disables the PWM output. The next set call will reenable the output. */
public void setDisabled() {
PWMJNI.setPWMDisabled(m_handle);
}
@@ -251,10 +242,19 @@
}
}
- protected void setZeroLatch() {
+ public void setZeroLatch() {
PWMJNI.latchPWMZero(m_handle);
}
+ /**
+ * Get the underlying handle.
+ *
+ * @return Underlying PWM handle
+ */
+ public int getHandle() {
+ return m_handle;
+ }
+
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("PWM");
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSparkMax.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSparkMax.java
deleted file mode 100644
index 0f97ea5..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSparkMax.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * REV Robotics SPARK MAX Speed Controller with PWM control.
- *
- * <P>Note that the SPARK MAX uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the SPARK MAX User Manual
- * available from REV Robotics.
- *
- * <p><ul>
- * <li> 2.003ms = full "forward"
- * <li> 1.550ms = the "high end" of the deadband range
- * <li> 1.500ms = center of the deadband range (off)
- * <li> 1.460ms = the "low end" of the deadband range
- * <li> 0.999ms = full "reverse"
- * </ul>
- */
-public class PWMSparkMax extends PWMSpeedController {
- /**
- * Common initialization code called by all constructors.
- *
- */
- public PWMSparkMax(final int channel) {
- super(channel);
-
- setBounds(2.003, 1.55, 1.50, 1.46, 0.999);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_RevSparkMaxPWM, getChannel() + 1);
- SendableRegistry.setName(this, "PWMSparkMax", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSpeedController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSpeedController.java
deleted file mode 100644
index 0a33423..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMSpeedController.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-
-/**
- * Common base class for all PWM Speed Controllers.
- */
-public abstract class PWMSpeedController extends PWM implements SpeedController {
- private boolean m_isInverted;
-
- /**
- * Constructor.
- *
- * @param channel The PWM channel that the controller is attached to. 0-9 are on-board, 10-19 are
- * on the MXP port
- */
- protected PWMSpeedController(int channel) {
- super(channel);
- }
-
- @Override
- public String getDescription() {
- return "PWM " + getChannel();
- }
-
- /**
- * Set the PWM value.
- *
- * <p>The PWM value is set using a range of -1.0 to 1.0, appropriately scaling the value for the
- * FPGA.
- *
- * @param speed The speed value between -1.0 and 1.0 to set.
- */
- @Override
- public void set(double speed) {
- setSpeed(m_isInverted ? -speed : speed);
- feed();
- }
-
- /**
- * Get the recently set value of the PWM.
- *
- * @return The most recently set value for the PWM between -1.0 and 1.0.
- */
- @Override
- public double get() {
- return getSpeed();
- }
-
- @Override
- public void setInverted(boolean isInverted) {
- m_isInverted = isInverted;
- }
-
- @Override
- public boolean getInverted() {
- return m_isInverted;
- }
-
- @Override
- public void disable() {
- setDisabled();
- }
-
- /**
- * Write out the PID value as seen in the PIDOutput base object.
- *
- * @param output Write out the PWM value as was found in the PIDController
- */
- @Override
- public void pidWrite(double output) {
- set(output);
- }
-
- @Override
- public void initSendable(SendableBuilder builder) {
- builder.setSmartDashboardType("Speed Controller");
- builder.setActuator(true);
- builder.setSafeState(this::setDisabled);
- builder.addDoubleProperty("Value", this::getSpeed, this::setSpeed);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonFX.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonFX.java
deleted file mode 100644
index 03acab2..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonFX.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Cross the Road Electronics (CTRE) Talon FX Speed Controller with PWM control.
- *
- * <p>Note that the TalonFX uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the TalonFX User Manual
- * available from CTRE.
- *
- * <p><ul>
- * <li>2.004ms = full "forward"
- * <li>1.520ms = the "high end" of the deadband range
- * <li>1.500ms = center of the deadband range (off)
- * <li>1.480ms = the "low end" of the deadband range
- * <li>0.997ms = full "reverse"
- * </ul>
- */
-public class PWMTalonFX extends PWMSpeedController {
- /**
- * Constructor for a TalonFX connected via PWM.
- *
- * @param channel The PWM channel that the Talon FX is attached to. 0-9 are on-board, 10-19 are
- * on the MXP port
- */
- public PWMTalonFX(final int channel) {
- super(channel);
-
- setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_TalonFX, getChannel() + 1);
- SendableRegistry.setName(this, "PWMTalonFX", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonSRX.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonSRX.java
deleted file mode 100644
index 1859e7f..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMTalonSRX.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Cross the Road Electronics (CTRE) Talon SRX Speed Controller with PWM control.
- *
- * <p>Note that the TalonSRX uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the TalonSRX User Manual
- * available from CTRE.
- *
- * <p><ul>
- * <li>2.004ms = full "forward"
- * <li>1.520ms = the "high end" of the deadband range
- * <li>1.500ms = center of the deadband range (off)
- * <li>1.480ms = the "low end" of the deadband range
- * <li>0.997ms = full "reverse"
- * </ul>
- */
-public class PWMTalonSRX extends PWMSpeedController {
- /**
- * Constructor for a TalonSRX connected via PWM.
- *
- * @param channel The PWM channel that the Talon SRX is attached to. 0-9 are on-board, 10-19 are
- * on the MXP port
- */
- public PWMTalonSRX(final int channel) {
- super(channel);
-
- setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_PWMTalonSRX, getChannel() + 1);
- SendableRegistry.setName(this, "PWMTalonSRX", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVenom.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVenom.java
deleted file mode 100644
index 9a1116d..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVenom.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Playing with Fusion Venom Smart Motor with PWM control.
- *
- * <p>Note that the Venom uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended.
- *
- * <p><ul>
- * <li>2.004ms = full "forward"
- * <li>1.520ms = the "high end" of the deadband range
- * <li>1.500ms = center of the deadband range (off)
- * <li>1.480ms = the "low end" of the deadband range
- * <li>0.997ms = full "reverse"
- * </ul>
- */
-public class PWMVenom extends PWMSpeedController {
- /**
- * Constructor for a Venom connected via PWM.
- *
- * @param channel The PWM channel that the Venom is attached to. 0-9 are on-board, 10-19 are
- * on the MXP port
- */
- public PWMVenom(final int channel) {
- super(channel);
-
- setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_FusionVenom, getChannel() + 1);
- SendableRegistry.setName(this, "PWMVenom", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVictorSPX.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVictorSPX.java
deleted file mode 100644
index b51686a..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PWMVictorSPX.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Cross the Road Electronics (CTRE) Victor SPX Speed Controller with PWM control.
- *
- * <p>Note that the Victor SPX uses the following bounds for PWM values. These values should
- * work reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the Victor SPX User
- * Manual available from CTRE.
- *
- * <p><ul>
- * <li>2.004ms = full "forward"
- * <li>1.520ms = the "high end" of the deadband range
- * <li>1.500ms = center of the deadband range (off)
- * <li>1.480ms = the "low end" of the deadband range
- * <li>0.997ms = full "reverse"
- * </ul>
- */
-public class PWMVictorSPX extends PWMSpeedController {
- /**
- * Constructor for a Victor SPX connected via PWM.
- *
- * @param channel The PWM channel that the PWMVictorSPX is attached to. 0-9 are on-board, 10-19
- * are on the MXP port
- */
- public PWMVictorSPX(final int channel) {
- super(channel);
-
- setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_PWMVictorSPX, getChannel() + 1);
- SendableRegistry.setName(this, "PWMVictorSPX", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticHub.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticHub.java
new file mode 100644
index 0000000..546c7c0
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticHub.java
@@ -0,0 +1,203 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.hal.REVPHJNI;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Module class for controlling a REV Robotics Pneumatic Hub. */
+public class PneumaticHub implements PneumaticsBase {
+ private static class DataStore implements AutoCloseable {
+ public final int m_module;
+ public final int m_handle;
+ private int m_refCount;
+ private int m_reservedMask;
+ private boolean m_compressorReserved;
+ private final Object m_reserveLock = new Object();
+
+ DataStore(int module) {
+ m_handle = REVPHJNI.initialize(module);
+ m_module = module;
+ m_handleMap.put(module, this);
+ }
+
+ @Override
+ public void close() {
+ REVPHJNI.free(m_handle);
+ m_handleMap.remove(m_module);
+ }
+
+ public void addRef() {
+ m_refCount++;
+ }
+
+ public void removeRef() {
+ m_refCount--;
+ if (m_refCount == 0) {
+ this.close();
+ }
+ }
+ }
+
+ private static final Map<Integer, DataStore> m_handleMap = new HashMap<>();
+ private static final Object m_handleLock = new Object();
+
+ private static DataStore getForModule(int module) {
+ synchronized (m_handleLock) {
+ Integer moduleBoxed = module;
+ DataStore pcm = m_handleMap.get(moduleBoxed);
+ if (pcm == null) {
+ pcm = new DataStore(module);
+ }
+ pcm.addRef();
+ return pcm;
+ }
+ }
+
+ private static void freeModule(DataStore store) {
+ synchronized (m_handleLock) {
+ store.removeRef();
+ }
+ }
+
+ private final DataStore m_dataStore;
+ private final int m_handle;
+
+ /** Constructs a PneumaticHub with the default id (1). */
+ public PneumaticHub() {
+ this(SensorUtil.getDefaultREVPHModule());
+ }
+
+ /**
+ * Constructs a PneumaticHub.
+ *
+ * @param module module number to construct
+ */
+ public PneumaticHub(int module) {
+ m_dataStore = getForModule(module);
+ m_handle = m_dataStore.m_handle;
+ }
+
+ @Override
+ public void close() {
+ freeModule(m_dataStore);
+ }
+
+ @Override
+ public boolean getCompressor() {
+ return REVPHJNI.getCompressor(m_handle);
+ }
+
+ @Override
+ public void setClosedLoopControl(boolean enabled) {
+ REVPHJNI.setClosedLoopControl(m_handle, enabled);
+ }
+
+ @Override
+ public boolean getClosedLoopControl() {
+ return REVPHJNI.getClosedLoopControl(m_handle);
+ }
+
+ @Override
+ public boolean getPressureSwitch() {
+ return REVPHJNI.getPressureSwitch(m_handle);
+ }
+
+ @Override
+ public double getCompressorCurrent() {
+ return REVPHJNI.getCompressorCurrent(m_handle);
+ }
+
+ @Override
+ public void setSolenoids(int mask, int values) {
+ REVPHJNI.setSolenoids(m_handle, mask, values);
+ }
+
+ @Override
+ public int getSolenoids() {
+ return REVPHJNI.getSolenoids(m_handle);
+ }
+
+ @Override
+ public int getModuleNumber() {
+ return m_dataStore.m_module;
+ }
+
+ @Override
+ public void fireOneShot(int index) {
+ // TODO Combine APIs
+ // REVPHJNI.fireOneShot(m_handle, index, durMs);
+ }
+
+ @Override
+ public void setOneShotDuration(int index, int durMs) {
+ // TODO Combine APIs
+ // REVPHJNI.setOneShotDuration(m_handle, index, durMs);
+ }
+
+ @Override
+ public boolean checkSolenoidChannel(int channel) {
+ return REVPHJNI.checkSolenoidChannel(channel);
+ }
+
+ @Override
+ public int checkAndReserveSolenoids(int mask) {
+ synchronized (m_dataStore.m_reserveLock) {
+ if ((m_dataStore.m_reservedMask & mask) != 0) {
+ return m_dataStore.m_reservedMask & mask;
+ }
+ m_dataStore.m_reservedMask |= mask;
+ return 0;
+ }
+ }
+
+ @Override
+ public void unreserveSolenoids(int mask) {
+ synchronized (m_dataStore.m_reserveLock) {
+ m_dataStore.m_reservedMask &= ~mask;
+ }
+ }
+
+ @Override
+ public Solenoid makeSolenoid(int channel) {
+ return new Solenoid(m_dataStore.m_module, PneumaticsModuleType.REVPH, channel);
+ }
+
+ @Override
+ public DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel) {
+ return new DoubleSolenoid(
+ m_dataStore.m_module, PneumaticsModuleType.REVPH, forwardChannel, reverseChannel);
+ }
+
+ @Override
+ public Compressor makeCompressor() {
+ return new Compressor(m_dataStore.m_module, PneumaticsModuleType.REVPH);
+ }
+
+ @Override
+ public boolean reserveCompressor() {
+ synchronized (m_dataStore.m_reserveLock) {
+ if (m_dataStore.m_compressorReserved) {
+ return false;
+ }
+ m_dataStore.m_compressorReserved = true;
+ return true;
+ }
+ }
+
+ @Override
+ public void unreserveCompressor() {
+ synchronized (m_dataStore.m_reserveLock) {
+ m_dataStore.m_compressorReserved = false;
+ }
+ }
+
+ @Override
+ public int getSolenoidDisabledList() {
+ // TODO Get this working
+ return 0;
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsBase.java
new file mode 100644
index 0000000..67c0f25
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsBase.java
@@ -0,0 +1,128 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+public interface PneumaticsBase extends AutoCloseable {
+ /**
+ * For internal use to get a module for a specific type.
+ *
+ * @param module module number
+ * @param type module type
+ * @return module
+ */
+ static PneumaticsBase getForType(int module, PneumaticsModuleType type) {
+ if (type == PneumaticsModuleType.CTREPCM) {
+ return new PneumaticsControlModule(module);
+ } else if (type == PneumaticsModuleType.REVPH) {
+ return new PneumaticHub(module);
+ }
+ throw new IllegalArgumentException("Unknown module type");
+ }
+
+ /**
+ * For internal use to get the default for a specific type.
+ *
+ * @param type module type
+ * @return module default
+ */
+ static int getDefaultForType(PneumaticsModuleType type) {
+ if (type == PneumaticsModuleType.CTREPCM) {
+ return SensorUtil.getDefaultCTREPCMModule();
+ } else if (type == PneumaticsModuleType.REVPH) {
+ return SensorUtil.getDefaultREVPHModule();
+ }
+ throw new IllegalArgumentException("Unknown module type");
+ }
+
+ /**
+ * Sets solenoids on a pneumatics module.
+ *
+ * @param mask mask
+ * @param values values
+ */
+ void setSolenoids(int mask, int values);
+
+ /**
+ * Gets solenoid values.
+ *
+ * @return values
+ */
+ int getSolenoids();
+
+ /**
+ * Get module number for this module.
+ *
+ * @return module number
+ */
+ int getModuleNumber();
+
+ /**
+ * Get the disabled solenoids.
+ *
+ * @return disabled list
+ */
+ int getSolenoidDisabledList();
+
+ /**
+ * Fire a single solenoid shot.
+ *
+ * @param index solenoid index
+ */
+ void fireOneShot(int index);
+
+ /**
+ * Set the duration for a single solenoid shot.
+ *
+ * @param index solenoid index
+ * @param durMs shot duration
+ */
+ void setOneShotDuration(int index, int durMs);
+
+ boolean getCompressor();
+
+ boolean getPressureSwitch();
+
+ double getCompressorCurrent();
+
+ void setClosedLoopControl(boolean on);
+
+ boolean getClosedLoopControl();
+
+ /**
+ * Check if a solenoid channel is valid.
+ *
+ * @param channel Channel to check
+ * @return True if channel exists
+ */
+ boolean checkSolenoidChannel(int channel);
+
+ /**
+ * Check to see if the masked solenoids can be reserved, and if not reserve them.
+ *
+ * @param mask The solenoid mask to reserve
+ * @return 0 if successful, mask of solenoids that couldn't be allocated otherwise
+ */
+ int checkAndReserveSolenoids(int mask);
+
+ /**
+ * Unreserve the masked solenoids.
+ *
+ * @param mask The solenoid mask to unreserve
+ */
+ void unreserveSolenoids(int mask);
+
+ boolean reserveCompressor();
+
+ void unreserveCompressor();
+
+ @Override
+ void close();
+
+ Solenoid makeSolenoid(int channel);
+
+ DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel);
+
+ Compressor makeCompressor();
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsControlModule.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsControlModule.java
new file mode 100644
index 0000000..79f245b
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsControlModule.java
@@ -0,0 +1,236 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.hal.CTREPCMJNI;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Module class for controlling a Cross The Road Electronics Pneumatics Control Module. */
+public class PneumaticsControlModule implements PneumaticsBase {
+ private static class DataStore implements AutoCloseable {
+ public final int m_module;
+ public final int m_handle;
+ private int m_refCount;
+ private int m_reservedMask;
+ private boolean m_compressorReserved;
+ private final Object m_reserveLock = new Object();
+
+ DataStore(int module) {
+ m_handle = CTREPCMJNI.initialize(module);
+ m_module = module;
+ m_handleMap.put(module, this);
+ }
+
+ @Override
+ public void close() {
+ CTREPCMJNI.free(m_handle);
+ m_handleMap.remove(m_module);
+ }
+
+ public void addRef() {
+ m_refCount++;
+ }
+
+ public void removeRef() {
+ m_refCount--;
+ if (m_refCount == 0) {
+ this.close();
+ }
+ }
+ }
+
+ private static final Map<Integer, DataStore> m_handleMap = new HashMap<>();
+ private static final Object m_handleLock = new Object();
+
+ private static DataStore getForModule(int module) {
+ synchronized (m_handleLock) {
+ Integer moduleBoxed = module;
+ DataStore pcm = m_handleMap.get(moduleBoxed);
+ if (pcm == null) {
+ pcm = new DataStore(module);
+ }
+ pcm.addRef();
+ return pcm;
+ }
+ }
+
+ private static void freeModule(DataStore store) {
+ synchronized (m_handleLock) {
+ store.removeRef();
+ }
+ }
+
+ private final DataStore m_dataStore;
+ private final int m_handle;
+
+ /** Constructs a PneumaticsControlModule with the default id (0). */
+ public PneumaticsControlModule() {
+ this(SensorUtil.getDefaultCTREPCMModule());
+ }
+
+ /**
+ * Constructs a PneumaticsControlModule.
+ *
+ * @param module module number to construct
+ */
+ public PneumaticsControlModule(int module) {
+ m_dataStore = getForModule(module);
+ m_handle = m_dataStore.m_handle;
+ }
+
+ @Override
+ public void close() {
+ freeModule(m_dataStore);
+ }
+
+ @Override
+ public boolean getCompressor() {
+ return CTREPCMJNI.getCompressor(m_handle);
+ }
+
+ @Override
+ public void setClosedLoopControl(boolean enabled) {
+ CTREPCMJNI.setClosedLoopControl(m_handle, enabled);
+ }
+
+ @Override
+ public boolean getClosedLoopControl() {
+ return CTREPCMJNI.getClosedLoopControl(m_handle);
+ }
+
+ @Override
+ public boolean getPressureSwitch() {
+ return CTREPCMJNI.getPressureSwitch(m_handle);
+ }
+
+ @Override
+ public double getCompressorCurrent() {
+ return CTREPCMJNI.getCompressorCurrent(m_handle);
+ }
+
+ public boolean getCompressorCurrentTooHighFault() {
+ return CTREPCMJNI.getCompressorCurrentTooHighFault(m_handle);
+ }
+
+ public boolean getCompressorCurrentTooHighStickyFault() {
+ return CTREPCMJNI.getCompressorCurrentTooHighStickyFault(m_handle);
+ }
+
+ public boolean getCompressorShortedFault() {
+ return CTREPCMJNI.getCompressorShortedFault(m_handle);
+ }
+
+ public boolean getCompressorShortedStickyFault() {
+ return CTREPCMJNI.getCompressorShortedStickyFault(m_handle);
+ }
+
+ public boolean getCompressorNotConnectedFault() {
+ return CTREPCMJNI.getCompressorNotConnectedFault(m_handle);
+ }
+
+ public boolean getCompressorNotConnectedStickyFault() {
+ return CTREPCMJNI.getCompressorNotConnectedStickyFault(m_handle);
+ }
+
+ @Override
+ public void setSolenoids(int mask, int values) {
+ CTREPCMJNI.setSolenoids(m_handle, mask, values);
+ }
+
+ @Override
+ public int getSolenoids() {
+ return CTREPCMJNI.getSolenoids(m_handle);
+ }
+
+ @Override
+ public int getModuleNumber() {
+ return m_dataStore.m_module;
+ }
+
+ @Override
+ public int getSolenoidDisabledList() {
+ return CTREPCMJNI.getSolenoidDisabledList(m_handle);
+ }
+
+ public boolean getSolenoidVoltageFault() {
+ return CTREPCMJNI.getSolenoidVoltageFault(m_handle);
+ }
+
+ public boolean getSolenoidVoltageStickyFault() {
+ return CTREPCMJNI.getSolenoidVoltageStickyFault(m_handle);
+ }
+
+ public void clearAllStickyFaults() {
+ CTREPCMJNI.clearAllStickyFaults(m_handle);
+ }
+
+ @Override
+ public void fireOneShot(int index) {
+ CTREPCMJNI.fireOneShot(m_handle, index);
+ }
+
+ @Override
+ public void setOneShotDuration(int index, int durMs) {
+ CTREPCMJNI.setOneShotDuration(m_handle, index, durMs);
+ }
+
+ @Override
+ public boolean checkSolenoidChannel(int channel) {
+ return CTREPCMJNI.checkSolenoidChannel(channel);
+ }
+
+ @Override
+ public int checkAndReserveSolenoids(int mask) {
+ synchronized (m_dataStore.m_reserveLock) {
+ if ((m_dataStore.m_reservedMask & mask) != 0) {
+ return m_dataStore.m_reservedMask & mask;
+ }
+ m_dataStore.m_reservedMask |= mask;
+ return 0;
+ }
+ }
+
+ @Override
+ public void unreserveSolenoids(int mask) {
+ synchronized (m_dataStore.m_reserveLock) {
+ m_dataStore.m_reservedMask &= ~mask;
+ }
+ }
+
+ @Override
+ public Solenoid makeSolenoid(int channel) {
+ return new Solenoid(m_dataStore.m_module, PneumaticsModuleType.CTREPCM, channel);
+ }
+
+ @Override
+ public DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel) {
+ return new DoubleSolenoid(
+ m_dataStore.m_module, PneumaticsModuleType.CTREPCM, forwardChannel, reverseChannel);
+ }
+
+ @Override
+ public Compressor makeCompressor() {
+ return new Compressor(m_dataStore.m_module, PneumaticsModuleType.CTREPCM);
+ }
+
+ @Override
+ public boolean reserveCompressor() {
+ synchronized (m_dataStore.m_reserveLock) {
+ if (m_dataStore.m_compressorReserved) {
+ return false;
+ }
+ m_dataStore.m_compressorReserved = true;
+ return true;
+ }
+ }
+
+ @Override
+ public void unreserveCompressor() {
+ synchronized (m_dataStore.m_reserveLock) {
+ m_dataStore.m_compressorReserved = false;
+ }
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsModuleType.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsModuleType.java
new file mode 100644
index 0000000..a7951e8
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PneumaticsModuleType.java
@@ -0,0 +1,10 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+public enum PneumaticsModuleType {
+ CTREPCM,
+ REVPH;
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistribution.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistribution.java
new file mode 100644
index 0000000..dd97efa
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistribution.java
@@ -0,0 +1,170 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.hal.PowerDistributionJNI;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
+
+/**
+ * Class for getting voltage, current, temperature, power and energy from the Power Distribution
+ * Panel over CAN.
+ */
+public class PowerDistribution implements Sendable, AutoCloseable {
+ private final int m_handle;
+ private final int m_module;
+
+ public static final int kDefaultModule = PowerDistributionJNI.DEFAULT_MODULE;
+
+ public enum ModuleType {
+ kAutomatic(PowerDistributionJNI.AUTOMATIC_TYPE),
+ kCTRE(PowerDistributionJNI.CTRE_TYPE),
+ kRev(PowerDistributionJNI.REV_TYPE);
+
+ public final int value;
+
+ ModuleType(int value) {
+ this.value = value;
+ }
+ }
+
+ /**
+ * Constructs a PowerDistribution.
+ *
+ * @param module The CAN ID of the PDP.
+ * @param moduleType Module type (automatic, CTRE, or REV).
+ */
+ public PowerDistribution(int module, ModuleType moduleType) {
+ m_handle = PowerDistributionJNI.initialize(module, moduleType.value);
+ m_module = PowerDistributionJNI.getModuleNumber(m_handle);
+
+ HAL.report(tResourceType.kResourceType_PDP, m_module + 1);
+ SendableRegistry.addLW(this, "PowerDistribution", m_module);
+ }
+
+ /**
+ * Constructs a PowerDistribution.
+ *
+ * <p>Uses the default CAN ID.
+ */
+ public PowerDistribution() {
+ this(kDefaultModule, ModuleType.kAutomatic);
+ }
+
+ @Override
+ public void close() {
+ SendableRegistry.remove(this);
+ }
+
+ /**
+ * Gets the number of channel for this power distribution.
+ *
+ * @return Number of output channels.
+ */
+ public int getNumChannels() {
+ return PowerDistributionJNI.getNumChannels(m_handle);
+ }
+
+ /**
+ * Query the input voltage of the PDP.
+ *
+ * @return The voltage of the PDP in volts
+ */
+ public double getVoltage() {
+ return PowerDistributionJNI.getVoltage(m_handle);
+ }
+
+ /**
+ * Query the temperature of the PDP.
+ *
+ * @return The temperature of the PDP in degrees Celsius
+ */
+ public double getTemperature() {
+ return PowerDistributionJNI.getTemperature(m_handle);
+ }
+
+ /**
+ * Query the current of a single channel of the PDP.
+ *
+ * @param channel The PDP channel to query.
+ * @return The current of one of the PDP channels (channels 0-15) in Amperes
+ */
+ public double getCurrent(int channel) {
+ double current = PowerDistributionJNI.getChannelCurrent(m_handle, channel);
+
+ return current;
+ }
+
+ /**
+ * Query the current of all monitored PDP channels (0-15).
+ *
+ * @return The current of all the channels in Amperes
+ */
+ public double getTotalCurrent() {
+ return PowerDistributionJNI.getTotalCurrent(m_handle);
+ }
+
+ /**
+ * Query the total power drawn from the monitored PDP channels.
+ *
+ * @return the total power in Watts
+ */
+ public double getTotalPower() {
+ return PowerDistributionJNI.getTotalPower(m_handle);
+ }
+
+ /**
+ * Query the total energy drawn from the monitored PDP channels.
+ *
+ * @return the total energy in Joules
+ */
+ public double getTotalEnergy() {
+ return PowerDistributionJNI.getTotalEnergy(m_handle);
+ }
+
+ /** Reset the total energy to 0. */
+ public void resetTotalEnergy() {
+ PowerDistributionJNI.resetTotalEnergy(m_handle);
+ }
+
+ /** Clear all PDP sticky faults. */
+ public void clearStickyFaults() {
+ PowerDistributionJNI.clearStickyFaults(m_handle);
+ }
+
+ /**
+ * Gets module number (CAN ID).
+ *
+ * @return The module number (CAN ID).
+ */
+ public int getModule() {
+ return m_module;
+ }
+
+ public boolean getSwitchableChannel() {
+ return PowerDistributionJNI.getSwitchableChannel(m_handle);
+ }
+
+ public void setSwitchableChannel(boolean enabled) {
+ PowerDistributionJNI.setSwitchableChannel(m_handle, enabled);
+ }
+
+ @Override
+ public void initSendable(SendableBuilder builder) {
+ builder.setSmartDashboardType("PowerDistribution");
+ int numChannels = getNumChannels();
+ for (int i = 0; i < numChannels; ++i) {
+ final int chan = i;
+ builder.addDoubleProperty("Chan" + i, () -> getCurrent(chan), null);
+ }
+ builder.addDoubleProperty("Voltage", this::getVoltage, null);
+ builder.addDoubleProperty("TotalCurrent", this::getTotalCurrent, null);
+ builder.addBooleanProperty(
+ "SwitchableChannel", this::getSwitchableChannel, this::setSwitchableChannel);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistributionPanel.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistributionPanel.java
deleted file mode 100644
index ef46028..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/PowerDistributionPanel.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2014-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.hal.PDPJNI;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Class for getting voltage, current, temperature, power and energy from the Power Distribution
- * Panel over CAN.
- */
-public class PowerDistributionPanel implements Sendable, AutoCloseable {
- private final int m_handle;
- private final int m_module;
-
- /**
- * Constructor.
- *
- * @param module The CAN ID of the PDP
- */
- public PowerDistributionPanel(int module) {
- SensorUtil.checkPDPModule(module);
- m_handle = PDPJNI.initializePDP(module);
- m_module = module;
-
- HAL.report(tResourceType.kResourceType_PDP, module + 1);
- SendableRegistry.addLW(this, "PowerDistributionPanel", module);
- }
-
- /**
- * Constructor. Uses the default CAN ID (0).
- */
- public PowerDistributionPanel() {
- this(0);
- }
-
- @Override
- public void close() {
- SendableRegistry.remove(this);
- }
-
- /**
- * Query the input voltage of the PDP.
- *
- * @return The voltage of the PDP in volts
- */
- public double getVoltage() {
- return PDPJNI.getPDPVoltage(m_handle);
- }
-
- /**
- * Query the temperature of the PDP.
- *
- * @return The temperature of the PDP in degrees Celsius
- */
- public double getTemperature() {
- return PDPJNI.getPDPTemperature(m_handle);
- }
-
- /**
- * Query the current of a single channel of the PDP.
- *
- * @return The current of one of the PDP channels (channels 0-15) in Amperes
- */
- public double getCurrent(int channel) {
- double current = PDPJNI.getPDPChannelCurrent((byte) channel, m_handle);
-
- SensorUtil.checkPDPChannel(channel);
-
- return current;
- }
-
- /**
- * Query the current of all monitored PDP channels (0-15).
- *
- * @return The current of all the channels in Amperes
- */
- public double getTotalCurrent() {
- return PDPJNI.getPDPTotalCurrent(m_handle);
- }
-
- /**
- * Query the total power drawn from the monitored PDP channels.
- *
- * @return the total power in Watts
- */
- public double getTotalPower() {
- return PDPJNI.getPDPTotalPower(m_handle);
- }
-
- /**
- * Query the total energy drawn from the monitored PDP channels.
- *
- * @return the total energy in Joules
- */
- public double getTotalEnergy() {
- return PDPJNI.getPDPTotalEnergy(m_handle);
- }
-
- /**
- * Reset the total energy to 0.
- */
- public void resetTotalEnergy() {
- PDPJNI.resetPDPTotalEnergy(m_handle);
- }
-
- /**
- * Clear all PDP sticky faults.
- */
- public void clearStickyFaults() {
- PDPJNI.clearPDPStickyFaults(m_handle);
- }
-
- /**
- * Gets module number (CAN ID).
- */
- public int getModule() {
- return m_module;
- }
-
- @Override
- public void initSendable(SendableBuilder builder) {
- builder.setSmartDashboardType("PowerDistributionPanel");
- for (int i = 0; i < SensorUtil.kPDPChannels; ++i) {
- final int chan = i;
- builder.addDoubleProperty("Chan" + i, () -> getCurrent(chan), null);
- }
- builder.addDoubleProperty("Voltage", this::getVoltage, null);
- builder.addDoubleProperty("TotalCurrent", this::getTotalCurrent, null);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Preferences.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Preferences.java
index 0edbbf3..a15fb70 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Preferences.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Preferences.java
@@ -1,13 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.Collection;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
@@ -15,41 +12,36 @@
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import java.util.Collection;
/**
* The preferences class provides a relatively simple way to save important values to the roboRIO to
* access the next time the roboRIO is booted.
*
- * <p> This class loads and saves from a file inside the roboRIO. The user can not access the file
+ * <p>This class loads and saves from a file inside the roboRIO. The user can not access the file
* directly, but may modify values at specific fields which will then be automatically saved to the
- * file by the NetworkTables server. </p>
+ * file by the NetworkTables server.
*
- * <p> This class is thread safe. </p>
+ * <p>This class is thread safe.
*
- * <p> This will also interact with {@link NetworkTable} by creating a table called "Preferences"
- * with all the key-value pairs. </p>
+ * <p>This will also interact with {@link NetworkTable} by creating a table called "Preferences"
+ * with all the key-value pairs.
*/
public final class Preferences {
- /**
- * The Preferences table name.
- */
+ /** The Preferences table name. */
private static final String TABLE_NAME = "Preferences";
- /**
- * The singleton instance.
- */
+ /** The singleton instance. */
private static Preferences instance;
- /**
- * The network table.
- */
- private final NetworkTable m_table;
+ /** The network table. */
+ private static final NetworkTable m_table;
/**
* Returns the preferences instance.
*
* @return the preferences instance
+ * @deprecated Use the static methods
*/
+ @Deprecated
public static synchronized Preferences getInstance() {
if (instance == null) {
instance = new Preferences();
@@ -57,10 +49,10 @@
return instance;
}
- /**
- * Creates a preference class.
- */
- private Preferences() {
+ /** Creates a preference class. */
+ private Preferences() {}
+
+ static {
m_table = NetworkTableInstance.getDefault().getTable(TABLE_NAME);
m_table.getEntry(".type").setString("RobotPreferences");
// Listener to set all Preferences values to persistent
@@ -73,21 +65,22 @@
/**
* Gets the preferences keys.
+ *
* @return a collection of the keys
*/
- public Collection<String> getKeys() {
+ public static Collection<String> getKeys() {
return m_table.getKeys();
}
/**
* Puts the given string into the preferences table.
*
- * @param key the key
+ * @param key the key
* @param value the value
* @throws NullPointerException if value is null
*/
- public void putString(String key, String value) {
- requireNonNullParam(value, "value", "putString");
+ public static void setString(String key, String value) {
+ requireNonNullParam(value, "value", "setString");
NetworkTableEntry entry = m_table.getEntry(key);
entry.setString(value);
@@ -95,12 +88,25 @@
}
/**
+ * Puts the given string into the preferences table.
+ *
+ * @param key the key
+ * @param value the value
+ * @throws NullPointerException if value is null
+ * @deprecated Use {@link #setString(String, String)}
+ */
+ @Deprecated
+ public static void putString(String key, String value) {
+ setString(key, value);
+ }
+
+ /**
* Puts the given string into the preferences table if it doesn't already exist.
*
- * @param key The key
+ * @param key The key
* @param value The value
*/
- public void initString(String key, String value) {
+ public static void initString(String key, String value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDefaultString(value);
}
@@ -108,22 +114,34 @@
/**
* Puts the given int into the preferences table.
*
- * @param key the key
+ * @param key the key
* @param value the value
*/
- public void putInt(String key, int value) {
+ public static void setInt(String key, int value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDouble(value);
entry.setPersistent();
}
/**
+ * Puts the given int into the preferences table.
+ *
+ * @param key the key
+ * @param value the value
+ * @deprecated Use {@link #setInt(String, int)}
+ */
+ @Deprecated
+ public static void putInt(String key, int value) {
+ setInt(key, value);
+ }
+
+ /**
* Puts the given int into the preferences table if it doesn't already exist.
*
- * @param key The key
+ * @param key The key
* @param value The value
*/
- public void initInt(String key, int value) {
+ public static void initInt(String key, int value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDefaultDouble(value);
}
@@ -131,22 +149,34 @@
/**
* Puts the given double into the preferences table.
*
- * @param key the key
+ * @param key the key
* @param value the value
*/
- public void putDouble(String key, double value) {
+ public static void setDouble(String key, double value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDouble(value);
entry.setPersistent();
}
/**
+ * Puts the given double into the preferences table.
+ *
+ * @param key the key
+ * @param value the value
+ * @deprecated Use {@link #setDouble(String, double)}
+ */
+ @Deprecated
+ public static void putDouble(String key, double value) {
+ setDouble(key, value);
+ }
+
+ /**
* Puts the given double into the preferences table if it doesn't already exist.
*
- * @param key The key
+ * @param key The key
* @param value The value
*/
- public void initDouble(String key, double value) {
+ public static void initDouble(String key, double value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDefaultDouble(value);
}
@@ -154,22 +184,34 @@
/**
* Puts the given float into the preferences table.
*
- * @param key the key
+ * @param key the key
* @param value the value
*/
- public void putFloat(String key, float value) {
+ public static void setFloat(String key, float value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDouble(value);
entry.setPersistent();
}
/**
+ * Puts the given float into the preferences table.
+ *
+ * @param key the key
+ * @param value the value
+ * @deprecated Use {@link #setFloat(String, float)}
+ */
+ @Deprecated
+ public static void putFloat(String key, float value) {
+ setFloat(key, value);
+ }
+
+ /**
* Puts the given float into the preferences table if it doesn't already exist.
*
- * @param key The key
+ * @param key The key
* @param value The value
*/
- public void initFloat(String key, float value) {
+ public static void initFloat(String key, float value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDefaultDouble(value);
}
@@ -177,22 +219,34 @@
/**
* Puts the given boolean into the preferences table.
*
- * @param key the key
+ * @param key the key
* @param value the value
*/
- public void putBoolean(String key, boolean value) {
+ public static void setBoolean(String key, boolean value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setBoolean(value);
entry.setPersistent();
}
/**
+ * Puts the given boolean into the preferences table.
+ *
+ * @param key the key
+ * @param value the value
+ * @deprecated Use {@link #setBoolean(String, boolean)}
+ */
+ @Deprecated
+ public static void putBoolean(String key, boolean value) {
+ setBoolean(key, value);
+ }
+
+ /**
* Puts the given boolean into the preferences table if it doesn't already exist.
*
- * @param key The key
+ * @param key The key
* @param value The value
*/
- public void initBoolean(String key, boolean value) {
+ public static void initBoolean(String key, boolean value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDefaultBoolean(value);
}
@@ -200,22 +254,34 @@
/**
* Puts the given long into the preferences table.
*
- * @param key the key
+ * @param key the key
* @param value the value
*/
- public void putLong(String key, long value) {
+ public static void setLong(String key, long value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDouble(value);
entry.setPersistent();
}
/**
+ * Puts the given long into the preferences table.
+ *
+ * @param key the key
+ * @param value the value
+ * @deprecated Use {@link #setLong(String, long)}
+ */
+ @Deprecated
+ public static void putLong(String key, long value) {
+ setLong(key, value);
+ }
+
+ /**
* Puts the given long into the preferences table if it doesn't already exist.
*
- * @param key The key
+ * @param key The key
* @param value The value
*/
- public void initLong(String key, long value) {
+ public static void initLong(String key, long value) {
NetworkTableEntry entry = m_table.getEntry(key);
entry.setDefaultDouble(value);
}
@@ -226,7 +292,7 @@
* @param key the key
* @return if there is a value at the given key
*/
- public boolean containsKey(String key) {
+ public static boolean containsKey(String key) {
return m_table.containsKey(key);
}
@@ -235,14 +301,12 @@
*
* @param key the key
*/
- public void remove(String key) {
+ public static void remove(String key) {
m_table.delete(key);
}
- /**
- * Remove all preferences.
- */
- public void removeAll() {
+ /** Remove all preferences. */
+ public static void removeAll() {
for (String key : m_table.getKeys()) {
if (!".type".equals(key)) {
remove(key);
@@ -254,11 +318,11 @@
* Returns the string at the given key. If this table does not have a value for that position,
* then the given backup value will be returned.
*
- * @param key the key
+ * @param key the key
* @param backup the value to return if none exists in the table
* @return either the value in the table, or the backup
*/
- public String getString(String key, String backup) {
+ public static String getString(String key, String backup) {
return m_table.getEntry(key).getString(backup);
}
@@ -266,11 +330,11 @@
* Returns the int at the given key. If this table does not have a value for that position, then
* the given backup value will be returned.
*
- * @param key the key
+ * @param key the key
* @param backup the value to return if none exists in the table
* @return either the value in the table, or the backup
*/
- public int getInt(String key, int backup) {
+ public static int getInt(String key, int backup) {
return (int) m_table.getEntry(key).getDouble(backup);
}
@@ -278,11 +342,11 @@
* Returns the double at the given key. If this table does not have a value for that position,
* then the given backup value will be returned.
*
- * @param key the key
+ * @param key the key
* @param backup the value to return if none exists in the table
* @return either the value in the table, or the backup
*/
- public double getDouble(String key, double backup) {
+ public static double getDouble(String key, double backup) {
return m_table.getEntry(key).getDouble(backup);
}
@@ -290,11 +354,11 @@
* Returns the boolean at the given key. If this table does not have a value for that position,
* then the given backup value will be returned.
*
- * @param key the key
+ * @param key the key
* @param backup the value to return if none exists in the table
* @return either the value in the table, or the backup
*/
- public boolean getBoolean(String key, boolean backup) {
+ public static boolean getBoolean(String key, boolean backup) {
return m_table.getEntry(key).getBoolean(backup);
}
@@ -302,11 +366,11 @@
* Returns the float at the given key. If this table does not have a value for that position, then
* the given backup value will be returned.
*
- * @param key the key
+ * @param key the key
* @param backup the value to return if none exists in the table
* @return either the value in the table, or the backup
*/
- public float getFloat(String key, float backup) {
+ public static float getFloat(String key, float backup) {
return (float) m_table.getEntry(key).getDouble(backup);
}
@@ -314,11 +378,11 @@
* Returns the long at the given key. If this table does not have a value for that position, then
* the given backup value will be returned.
*
- * @param key the key
+ * @param key the key
* @param backup the value to return if none exists in the table
* @return either the value in the table, or the backup
*/
- public long getLong(String key, long backup) {
+ public static long getLong(String key, long backup) {
return (long) m_table.getEntry(key).getDouble(backup);
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Relay.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Relay.java
index f379de4..05efebd 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Relay.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Relay.java
@@ -1,32 +1,30 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.Arrays;
-import java.util.Optional;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.RelayJNI;
+import edu.wpi.first.hal.util.HalHandleException;
import edu.wpi.first.hal.util.UncleanStatusException;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-import static edu.wpi.first.wpilibj.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.Arrays;
+import java.util.Optional;
/**
* Class for VEX Robotics Spike style relay outputs. Relays are intended to be connected to Spikes
* or similar relays. The relay channels controls a pair of channels that are either both off, one
- * on, the other on, or both on. This translates into two Spike outputs at 0v, one at 12v and one
- * at 0v, one at 0v and the other at 12v, or two Spike outputs at 12V. This allows off, full
- * forward, or full reverse control of motors without variable speed. It also allows the two
- * channels (forward and reverse) to be used independently for something that does not care about
- * voltage polarity (like a solenoid).
+ * on, the other on, or both on. This translates into two Spike outputs at 0v, one at 12v and one at
+ * 0v, one at 0v and the other at 12v, or two Spike outputs at 12V. This allows off, full forward,
+ * or full reverse control of motors without variable speed. It also allows the two channels
+ * (forward and reverse) to be used independently for something that does not care about voltage
+ * polarity (like a solenoid).
*/
public class Relay extends MotorSafety implements Sendable, AutoCloseable {
/**
@@ -45,9 +43,7 @@
}
}
- /**
- * The state to drive a Relay to.
- */
+ /** The state to drive a Relay to. */
public enum Value {
kOff("Off"),
kOn("On"),
@@ -69,22 +65,13 @@
}
}
- /**
- * The Direction(s) that a relay is configured to operate in.
- */
+ /** The Direction(s) that a relay is configured to operate in. */
public enum Direction {
- /**
- * direction: both directions are valid.
- */
-
+ /** direction: both directions are valid. */
kBoth,
- /**
- * direction: Only forward is valid.
- */
+ /** direction: Only forward is valid. */
kForward,
- /**
- * direction: only reverse is valid.
- */
+ /** direction: only reverse is valid. */
kReverse
}
@@ -149,12 +136,12 @@
private void freeRelay() {
try {
RelayJNI.setRelay(m_forwardHandle, false);
- } catch (UncleanStatusException ignored) {
+ } catch (UncleanStatusException | HalHandleException ignored) {
// do nothing. Ignore
}
try {
RelayJNI.setRelay(m_reverseHandle, false);
- } catch (UncleanStatusException ignored) {
+ } catch (UncleanStatusException | HalHandleException ignored) {
// do nothing. Ignore
}
@@ -178,7 +165,6 @@
*
* @param value The state to set the relay.
*/
- @SuppressWarnings("PMD.CyclomaticComplexity")
public void set(Value value) {
switch (value) {
case kOff:
@@ -199,8 +185,8 @@
break;
case kForward:
if (m_direction == Direction.kReverse) {
- throw new InvalidValueException("A relay configured for reverse cannot be set to "
- + "forward");
+ throw new InvalidValueException(
+ "A relay configured for reverse cannot be set to " + "forward");
}
if (m_direction == Direction.kBoth || m_direction == Direction.kForward) {
RelayJNI.setRelay(m_forwardHandle, true);
@@ -211,8 +197,8 @@
break;
case kReverse:
if (m_direction == Direction.kForward) {
- throw new InvalidValueException("A relay configured for forward cannot be set to "
- + "reverse");
+ throw new InvalidValueException(
+ "A relay configured for forward cannot be set to " + "reverse");
}
if (m_direction == Direction.kBoth) {
RelayJNI.setRelay(m_forwardHandle, false);
@@ -310,7 +296,9 @@
builder.setSmartDashboardType("Relay");
builder.setActuator(true);
builder.setSafeState(() -> set(Value.kOff));
- builder.addStringProperty("Value", () -> get().getPrettyValue(),
+ builder.addStringProperty(
+ "Value",
+ () -> get().getPrettyValue(),
value -> set(Value.getValueOf(value).orElse(Value.kOff)));
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Resource.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Resource.java
index 39a0eac..09137d6 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Resource.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Resource.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -29,9 +26,7 @@
private final int m_size;
private final Resource m_nextResource;
- /**
- * Clears all allocated resources.
- */
+ /** Clears all allocated resources. */
public static void restartProgram() {
for (Resource r = Resource.resourceList; r != null; r = r.m_nextResource) {
for (int i = 0; i < r.m_size; i++) {
@@ -42,8 +37,8 @@
/**
* Allocate storage for a new instance of Resource. Allocate a bool array of values that will get
- * initialized to indicate that no resources have been allocated yet. The indices of the
- * resources are 0..size-1.
+ * initialized to indicate that no resources have been allocated yet. The indices of the resources
+ * are 0..size-1.
*
* @param size The number of blocks to allocate
*/
@@ -106,5 +101,4 @@
}
m_numAllocated[index] = false;
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java
index 9c3e45f..8d1fb07 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java
@@ -1,23 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Supplier;
-
-import edu.wpi.cscore.CameraServerJNI;
import edu.wpi.first.cameraserver.CameraServerShared;
import edu.wpi.first.cameraserver.CameraServerSharedStore;
+import edu.wpi.first.cscore.CameraServerJNI;
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
@@ -29,6 +18,13 @@
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard;
import edu.wpi.first.wpilibj.util.WPILibVersion;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Supplier;
/**
* Implement a Robot Program framework. The RobotBase class is intended to be subclassed by a user
@@ -38,106 +34,107 @@
* might be spawned as a task, then killed at the end of the Autonomous period.
*/
public abstract class RobotBase implements AutoCloseable {
- /**
- * The ID of the main Java thread.
- */
+ /** The ID of the main Java thread. */
// This is usually 1, but it is best to make sure
private static long m_threadId = -1;
private static void setupCameraServerShared() {
- CameraServerShared shared = new CameraServerShared() {
+ CameraServerShared shared =
+ new CameraServerShared() {
+ @Override
+ public void reportVideoServer(int id) {
+ HAL.report(tResourceType.kResourceType_PCVideoServer, id + 1);
+ }
- @Override
- public void reportVideoServer(int id) {
- HAL.report(tResourceType.kResourceType_PCVideoServer, id + 1);
- }
+ @Override
+ public void reportUsbCamera(int id) {
+ HAL.report(tResourceType.kResourceType_UsbCamera, id + 1);
+ }
- @Override
- public void reportUsbCamera(int id) {
- HAL.report(tResourceType.kResourceType_UsbCamera, id + 1);
- }
+ @Override
+ public void reportDriverStationError(String error) {
+ DriverStation.reportError(error, true);
+ }
- @Override
- public void reportDriverStationError(String error) {
- DriverStation.reportError(error, true);
- }
+ @Override
+ public void reportAxisCamera(int id) {
+ HAL.report(tResourceType.kResourceType_AxisCamera, id + 1);
+ }
- @Override
- public void reportAxisCamera(int id) {
- HAL.report(tResourceType.kResourceType_AxisCamera, id + 1);
- }
+ @Override
+ public Long getRobotMainThreadId() {
+ return RobotBase.getMainThreadId();
+ }
- @Override
- public Long getRobotMainThreadId() {
- return RobotBase.getMainThreadId();
- }
-
- @Override
- public boolean isRoboRIO() {
- return RobotBase.isReal();
- }
- };
+ @Override
+ public boolean isRoboRIO() {
+ return RobotBase.isReal();
+ }
+ };
CameraServerSharedStore.setCameraServerShared(shared);
}
private static void setupMathShared() {
- MathSharedStore.setMathShared(new MathShared() {
- @Override
- public void reportError(String error, StackTraceElement[] stackTrace) {
- DriverStation.reportError(error, stackTrace);
- }
+ MathSharedStore.setMathShared(
+ new MathShared() {
+ @Override
+ public void reportError(String error, StackTraceElement[] stackTrace) {
+ DriverStation.reportError(error, stackTrace);
+ }
- @Override
- public void reportUsage(MathUsageId id, int count) {
- switch (id) {
- case kKinematics_DifferentialDrive:
- HAL.report(tResourceType.kResourceType_Kinematics,
- tInstances.kKinematics_DifferentialDrive);
- break;
- case kKinematics_MecanumDrive:
- HAL.report(tResourceType.kResourceType_Kinematics,
- tInstances.kKinematics_MecanumDrive);
- break;
- case kKinematics_SwerveDrive:
- HAL.report(tResourceType.kResourceType_Kinematics,
- tInstances.kKinematics_SwerveDrive);
- break;
- case kTrajectory_TrapezoidProfile:
- HAL.report(tResourceType.kResourceType_TrapezoidProfile, count);
- break;
- case kFilter_Linear:
- HAL.report(tResourceType.kResourceType_LinearFilter, count);
- break;
- case kOdometry_DifferentialDrive:
- HAL.report(tResourceType.kResourceType_Odometry,
- tInstances.kOdometry_DifferentialDrive);
- break;
- case kOdometry_SwerveDrive:
- HAL.report(tResourceType.kResourceType_Odometry,
- tInstances.kOdometry_SwerveDrive);
- break;
- case kOdometry_MecanumDrive:
- HAL.report(tResourceType.kResourceType_Odometry,
- tInstances.kOdometry_MecanumDrive);
- break;
- default:
- break;
- }
- }
- });
+ @Override
+ public void reportUsage(MathUsageId id, int count) {
+ switch (id) {
+ case kKinematics_DifferentialDrive:
+ HAL.report(
+ tResourceType.kResourceType_Kinematics,
+ tInstances.kKinematics_DifferentialDrive);
+ break;
+ case kKinematics_MecanumDrive:
+ HAL.report(
+ tResourceType.kResourceType_Kinematics, tInstances.kKinematics_MecanumDrive);
+ break;
+ case kKinematics_SwerveDrive:
+ HAL.report(
+ tResourceType.kResourceType_Kinematics, tInstances.kKinematics_SwerveDrive);
+ break;
+ case kTrajectory_TrapezoidProfile:
+ HAL.report(tResourceType.kResourceType_TrapezoidProfile, count);
+ break;
+ case kFilter_Linear:
+ HAL.report(tResourceType.kResourceType_LinearFilter, count);
+ break;
+ case kOdometry_DifferentialDrive:
+ HAL.report(
+ tResourceType.kResourceType_Odometry, tInstances.kOdometry_DifferentialDrive);
+ break;
+ case kOdometry_SwerveDrive:
+ HAL.report(tResourceType.kResourceType_Odometry, tInstances.kOdometry_SwerveDrive);
+ break;
+ case kOdometry_MecanumDrive:
+ HAL.report(tResourceType.kResourceType_Odometry, tInstances.kOdometry_MecanumDrive);
+ break;
+ case kController_PIDController2:
+ HAL.report(tResourceType.kResourceType_PIDController2, count);
+ break;
+ case kController_ProfiledPIDController:
+ HAL.report(tResourceType.kResourceType_ProfiledPIDController, count);
+ break;
+ default:
+ break;
+ }
+ }
+ });
}
- protected final DriverStation m_ds;
-
/**
* Constructor for a generic robot program. User code should be placed in the constructor that
* runs before the Autonomous or Operator Control period starts. The constructor will run to
* completion before Autonomous is entered.
*
* <p>This must be used to ensure that the communications code starts. In the future it would be
- * nice
- * to put this code into it's own task that loads on boot so ensure that it runs.
+ * nice to put this code into it's own task that loads on boot so ensure that it runs.
*/
protected RobotBase() {
final NetworkTableInstance inst = NetworkTableInstance.getDefault();
@@ -150,7 +147,6 @@
} else {
inst.startServer();
}
- m_ds = DriverStation.getInstance();
inst.getTable("LiveWindow").getSubTable(".status").getEntry("LW Enabled").setBoolean(false);
LiveWindow.setEnabled(false);
@@ -162,7 +158,15 @@
}
@Override
- public void close() {
+ public void close() {}
+
+ /**
+ * Get the current runtime type.
+ *
+ * @return Current runtime type.
+ */
+ public static RuntimeType getRuntimeType() {
+ return RuntimeType.getValue(HALUtil.getHALRuntimeType());
}
/**
@@ -180,7 +184,8 @@
* @return If the robot is running in the real world.
*/
public static boolean isReal() {
- return HALUtil.getHALRuntimeType() == 0;
+ RuntimeType runtimeType = getRuntimeType();
+ return runtimeType == RuntimeType.kRoboRIO || runtimeType == RuntimeType.kRoboRIO2;
}
/**
@@ -189,7 +194,7 @@
* @return True if the Robot is currently disabled by the field controls.
*/
public boolean isDisabled() {
- return m_ds.isDisabled();
+ return DriverStation.isDisabled();
}
/**
@@ -198,37 +203,47 @@
* @return True if the Robot is currently enabled by the field controls.
*/
public boolean isEnabled() {
- return m_ds.isEnabled();
+ return DriverStation.isEnabled();
}
/**
- * Determine if the robot is currently in Autonomous mode as determined by the field
- * controls.
+ * Determine if the robot is currently in Autonomous mode as determined by the field controls.
*
* @return True if the robot is currently operating Autonomously.
*/
public boolean isAutonomous() {
- return m_ds.isAutonomous();
+ return DriverStation.isAutonomous();
}
/**
- * Determine if the robot is current in Autonomous mode and enabled as determined by
- * the field controls.
+ * Determine if the robot is current in Autonomous mode and enabled as determined by the field
+ * controls.
*
* @return True if the robot is currently operating autonomously while enabled.
*/
public boolean isAutonomousEnabled() {
- return m_ds.isAutonomousEnabled();
+ return DriverStation.isAutonomousEnabled();
}
/**
- * Determine if the robot is currently in Test mode as determined by the driver
- * station.
+ * Determine if the robot is currently in Test mode as determined by the driver station.
*
* @return True if the robot is currently operating in Test mode.
*/
public boolean isTest() {
- return m_ds.isTest();
+ return DriverStation.isTest();
+ }
+
+ /**
+ * Determine if the robot is currently in Operator Control mode as determined by the field
+ * controls.
+ *
+ * @return True if the robot is currently operating in Tele-Op mode.
+ * @deprecated Use isTeleop() instead.
+ */
+ @Deprecated(since = "2022", forRemoval = true)
+ public boolean isOperatorControl() {
+ return DriverStation.isTeleop();
}
/**
@@ -237,18 +252,30 @@
*
* @return True if the robot is currently operating in Tele-Op mode.
*/
- public boolean isOperatorControl() {
- return m_ds.isOperatorControl();
+ public boolean isTeleop() {
+ return DriverStation.isTeleop();
}
/**
- * Determine if the robot is current in Operator Control mode and enabled as determined by
- * the field controls.
+ * Determine if the robot is current in Operator Control mode and enabled as determined by the
+ * field controls.
+ *
+ * @return True if the robot is currently operating in Tele-Op mode while enabled.
+ * @deprecated Use isTeleopEnabled() instead.
+ */
+ @Deprecated(since = "2022", forRemoval = true)
+ public boolean isOperatorControlEnabled() {
+ return DriverStation.isTeleopEnabled();
+ }
+
+ /**
+ * Determine if the robot is current in Operator Control mode and enabled as determined by the
+ * field controls.
*
* @return True if the robot is currently operating in Tele-Op mode while enabled.
*/
- public boolean isOperatorControlEnabled() {
- return m_ds.isOperatorControlEnabled();
+ public boolean isTeleopEnabled() {
+ return DriverStation.isTeleopEnabled();
}
/**
@@ -257,20 +284,16 @@
* @return Has new data arrived over the network since the last time this function was called?
*/
public boolean isNewDataAvailable() {
- return m_ds.isNewControlData();
+ return DriverStation.isNewControlData();
}
- /**
- * Provide an alternate "main loop" via startCompetition().
- */
+ /** Provide an alternate "main loop" via startCompetition(). */
public abstract void startCompetition();
- /**
- * Ends the main loop in startCompetition().
- */
+ /** Ends the main loop in startCompetition(). */
public abstract void endCompetition();
- @SuppressWarnings("JavadocMethod")
+ @SuppressWarnings("MissingJavadocMethod")
public static boolean getBooleanProperty(String name, boolean defaultValue) {
String propVal = System.getProperty(name);
if (propVal == null) {
@@ -289,11 +312,8 @@
private static RobotBase m_robotCopy;
private static boolean m_suppressExitWarning;
- /**
- * Run the robot main loop.
- */
- @SuppressWarnings({"PMD.AvoidInstantiatingObjectsInLoops", "PMD.AvoidCatchingThrowable",
- "PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
+ /** Run the robot main loop. */
+ @SuppressWarnings("PMD.AvoidCatchingThrowable")
private static <T extends RobotBase> void runRobot(Supplier<T> robotSupplier) {
System.out.println("********** Robot program starting **********");
@@ -310,9 +330,15 @@
if (elements.length > 0) {
robotName = elements[0].getClassName();
}
- DriverStation.reportError("Unhandled exception instantiating robot " + robotName + " "
- + throwable.toString(), elements);
- DriverStation.reportWarning("Robots should not quit, but yours did!", false);
+ DriverStation.reportError(
+ "Unhandled exception instantiating robot " + robotName + " " + throwable.toString(),
+ elements);
+ DriverStation.reportError(
+ "The robot program quit unexpectedly."
+ + " This is usually due to a code error.\n"
+ + " The above stacktrace can help determine where the error occurred.\n"
+ + " See https://wpilib.org/stacktrace for more information.\n",
+ false);
DriverStation.reportError("Could not instantiate robot " + robotName + "!", false);
return;
}
@@ -322,23 +348,23 @@
m_runMutex.unlock();
if (isReal()) {
+ final File file = new File("/tmp/frc_versions/FRC_Lib_Version.ini");
try {
- final File file = new File("/tmp/frc_versions/FRC_Lib_Version.ini");
-
- if (file.exists()) {
- file.delete();
+ if (file.exists() && !file.delete()) {
+ throw new IOException("Failed to delete FRC_Lib_Version.ini");
}
- file.createNewFile();
+ if (!file.createNewFile()) {
+ throw new IOException("Failed to create new FRC_Lib_Version.ini");
+ }
try (OutputStream output = Files.newOutputStream(file.toPath())) {
output.write("Java ".getBytes(StandardCharsets.UTF_8));
output.write(WPILibVersion.Version.getBytes(StandardCharsets.UTF_8));
}
-
} catch (IOException ex) {
- DriverStation.reportError("Could not write FRC_Lib_Version.ini: " + ex.toString(),
- ex.getStackTrace());
+ DriverStation.reportError(
+ "Could not write FRC_Lib_Version.ini: " + ex.toString(), ex.getStackTrace());
}
}
@@ -350,8 +376,8 @@
if (cause != null) {
throwable = cause;
}
- DriverStation.reportError("Unhandled exception: " + throwable.toString(),
- throwable.getStackTrace());
+ DriverStation.reportError(
+ "Unhandled exception: " + throwable.toString(), throwable.getStackTrace());
errorOnExit = true;
} finally {
m_runMutex.lock();
@@ -359,11 +385,17 @@
m_runMutex.unlock();
if (!suppressExitWarning) {
// startCompetition never returns unless exception occurs....
- DriverStation.reportWarning("Robots should not quit, but yours did!", false);
+ DriverStation.reportWarning(
+ "The robot program quit unexpectedly."
+ + " This is usually due to a code error.\n"
+ + " The above stacktrace can help determine where the error occurred.\n"
+ + " See https://wpilib.org/stacktrace for more information.",
+ false);
if (errorOnExit) {
DriverStation.reportError(
"The startCompetition() method (or methods called by it) should have "
- + "handled the exception above.", false);
+ + "handled the exception above.",
+ false);
} else {
DriverStation.reportError("Unexpected return from startCompetition() method.", false);
}
@@ -372,7 +404,9 @@
}
/**
- * Suppress the "Robots should not quit" message.
+ * Suppress the "The robot program quit unexpectedly." message.
+ *
+ * @param value True if exit warning should be suppressed.
*/
public static void suppressExitWarning(boolean value) {
m_runMutex.lock();
@@ -382,6 +416,9 @@
/**
* Starting point for the applications.
+ *
+ * @param <T> Robot subclass.
+ * @param robotSupplier Function that returns an instance of the robot subclass.
*/
public static <T extends RobotBase> void startRobot(Supplier<T> robotSupplier) {
if (!HAL.initialize(500, 0)) {
@@ -392,14 +429,21 @@
// Needed because all the OpenCV JNI functions don't have built in loading
CameraServerJNI.enumerateSinks();
- HAL.report(tResourceType.kResourceType_Language, tInstances.kLanguage_Java, 0,
- WPILibVersion.Version);
+ HAL.report(
+ tResourceType.kResourceType_Language, tInstances.kLanguage_Java, 0, WPILibVersion.Version);
+
+ if (!Notifier.setHALThreadPriority(true, 40)) {
+ DriverStation.reportWarning("Setting HAL Notifier RT priority to 40 failed", false);
+ }
if (HAL.hasMain()) {
- Thread thread = new Thread(() -> {
- runRobot(robotSupplier);
- HAL.exitMain();
- }, "robot main");
+ Thread thread =
+ new Thread(
+ () -> {
+ runRobot(robotSupplier);
+ HAL.exitMain();
+ },
+ "robot main");
thread.setDaemon(true);
thread.start();
HAL.runMain();
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java
index 0623812..8a7460e 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -13,17 +10,14 @@
import edu.wpi.first.hal.can.CANJNI;
import edu.wpi.first.hal.can.CANStatus;
-/**
- * Contains functions for roboRIO functionality.
- */
+/** Contains functions for roboRIO functionality. */
public final class RobotController {
private RobotController() {
throw new UnsupportedOperationException("This is a utility class!");
}
/**
- * Return the FPGA Version number. For now, expect this to be the current
- * year.
+ * Return the FPGA Version number. For now, expect this to be the current year.
*
* @return FPGA Version number.
*/
@@ -120,7 +114,7 @@
/**
* Get the current output of the 3.3V rail.
*
- * @return The controller 3.3V rail output current value in Volts
+ * @return The controller 3.3V rail output current value in Amps
*/
public static double getCurrent3V3() {
return PowerJNI.getUserCurrent3V3();
@@ -220,13 +214,33 @@
}
/**
+ * Get the current brownout voltage setting.
+ *
+ * @return The brownout voltage
+ */
+ public static double getBrownoutVoltage() {
+ return PowerJNI.getBrownoutVoltage();
+ }
+
+ /**
+ * Set the voltage the roboRIO will brownout and disable all outputs.
+ *
+ * <p>Note that this only does anything on the roboRIO 2. On the roboRIO it is a no-op.
+ *
+ * @param brownoutVoltage The brownout voltage
+ */
+ public static void setBrownoutVoltage(double brownoutVoltage) {
+ PowerJNI.setBrownoutVoltage(brownoutVoltage);
+ }
+
+ /**
* Get the current status of the CAN bus.
*
* @return The status of the CAN bus
*/
public static CANStatus getCANStatus() {
CANStatus status = new CANStatus();
- CANJNI.GetCANStatus(status);
+ CANJNI.getCANStatus(status);
return status;
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java
deleted file mode 100644
index f79d74a..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotDrive.java
+++ /dev/null
@@ -1,716 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tInstances;
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
-
-/**
- * Utility class for handling Robot drive based on a definition of the motor configuration. The
- * robot drive class handles basic driving for a robot. Currently, 2 and 4 motor tank and mecanum
- * drive trains are supported. In the future other drive types like swerve might be implemented.
- * Motor channel numbers are supplied on creation of the class. Those are used for either the drive
- * function (intended for hand created drive code, such as autonomous) or with the Tank/Arcade
- * functions intended to be used for Operator Control driving.
- *
- * @deprecated Use {@link edu.wpi.first.wpilibj.drive.DifferentialDrive}
- * or {@link edu.wpi.first.wpilibj.drive.MecanumDrive} classes instead.
- */
-@Deprecated
-@SuppressWarnings("PMD.GodClass")
-public class RobotDrive extends MotorSafety implements AutoCloseable {
- /**
- * The location of a motor on the robot for the purpose of driving.
- */
- public enum MotorType {
- kFrontLeft(0), kFrontRight(1), kRearLeft(2), kRearRight(3);
-
- @SuppressWarnings("MemberName")
- public final int value;
-
- MotorType(int value) {
- this.value = value;
- }
- }
-
- public static final double kDefaultExpirationTime = 0.1;
- public static final double kDefaultSensitivity = 0.5;
- public static final double kDefaultMaxOutput = 1.0;
- protected static final int kMaxNumberOfMotors = 4;
- protected double m_sensitivity;
- protected double m_maxOutput;
- protected SpeedController m_frontLeftMotor;
- protected SpeedController m_frontRightMotor;
- protected SpeedController m_rearLeftMotor;
- protected SpeedController m_rearRightMotor;
- protected boolean m_allocatedSpeedControllers;
- protected static boolean kArcadeRatioCurve_Reported;
- protected static boolean kTank_Reported;
- protected static boolean kArcadeStandard_Reported;
- protected static boolean kMecanumCartesian_Reported;
- protected static boolean kMecanumPolar_Reported;
-
- /**
- * Constructor for RobotDrive with 2 motors specified with channel numbers. Set up parameters for
- * a two wheel drive system where the left and right motor pwm channels are specified in the call.
- * This call assumes Talons for controlling the motors.
- *
- * @param leftMotorChannel The PWM channel number that drives the left motor.
- * @param rightMotorChannel The PWM channel number that drives the right motor.
- */
- public RobotDrive(final int leftMotorChannel, final int rightMotorChannel) {
- m_sensitivity = kDefaultSensitivity;
- m_maxOutput = kDefaultMaxOutput;
- m_frontLeftMotor = null;
- m_rearLeftMotor = new Talon(leftMotorChannel);
- m_frontRightMotor = null;
- m_rearRightMotor = new Talon(rightMotorChannel);
- m_allocatedSpeedControllers = true;
- setSafetyEnabled(true);
- drive(0, 0);
- }
-
- /**
- * Constructor for RobotDrive with 4 motors specified with channel numbers. Set up parameters for
- * a four wheel drive system where all four motor pwm channels are specified in the call. This
- * call assumes Talons for controlling the motors.
- *
- * @param frontLeftMotor Front left motor channel number
- * @param rearLeftMotor Rear Left motor channel number
- * @param frontRightMotor Front right motor channel number
- * @param rearRightMotor Rear Right motor channel number
- */
- public RobotDrive(final int frontLeftMotor, final int rearLeftMotor, final int frontRightMotor,
- final int rearRightMotor) {
- m_sensitivity = kDefaultSensitivity;
- m_maxOutput = kDefaultMaxOutput;
- m_rearLeftMotor = new Talon(rearLeftMotor);
- m_rearRightMotor = new Talon(rearRightMotor);
- m_frontLeftMotor = new Talon(frontLeftMotor);
- m_frontRightMotor = new Talon(frontRightMotor);
- m_allocatedSpeedControllers = true;
- setSafetyEnabled(true);
- drive(0, 0);
- }
-
- /**
- * Constructor for RobotDrive with 2 motors specified as SpeedController objects. The
- * SpeedController version of the constructor enables programs to use the RobotDrive classes with
- * subclasses of the SpeedController objects, for example, versions with ramping or reshaping of
- * the curve to suit motor bias or dead-band elimination.
- *
- * @param leftMotor The left SpeedController object used to drive the robot.
- * @param rightMotor the right SpeedController object used to drive the robot.
- */
- public RobotDrive(SpeedController leftMotor, SpeedController rightMotor) {
- requireNonNullParam(leftMotor, "leftMotor", "RobotDrive");
- requireNonNullParam(rightMotor, "rightMotor", "RobotDrive");
-
- m_frontLeftMotor = null;
- m_rearLeftMotor = leftMotor;
- m_frontRightMotor = null;
- m_rearRightMotor = rightMotor;
- m_sensitivity = kDefaultSensitivity;
- m_maxOutput = kDefaultMaxOutput;
- m_allocatedSpeedControllers = false;
- setSafetyEnabled(true);
- drive(0, 0);
- }
-
- /**
- * Constructor for RobotDrive with 4 motors specified as SpeedController objects. Speed controller
- * input version of RobotDrive (see previous comments).
- *
- * @param frontLeftMotor The front left SpeedController object used to drive the robot
- * @param rearLeftMotor The back left SpeedController object used to drive the robot.
- * @param frontRightMotor The front right SpeedController object used to drive the robot.
- * @param rearRightMotor The back right SpeedController object used to drive the robot.
- */
- public RobotDrive(SpeedController frontLeftMotor, SpeedController rearLeftMotor,
- SpeedController frontRightMotor, SpeedController rearRightMotor) {
- m_frontLeftMotor = requireNonNullParam(frontLeftMotor, "frontLeftMotor", "RobotDrive");
- m_rearLeftMotor = requireNonNullParam(rearLeftMotor, "rearLeftMotor", "RobotDrive");
- m_frontRightMotor = requireNonNullParam(frontRightMotor, "frontRightMotor", "RobotDrive");
- m_rearRightMotor = requireNonNullParam(rearRightMotor, "rearRightMotor", "RobotDrive");
- m_sensitivity = kDefaultSensitivity;
- m_maxOutput = kDefaultMaxOutput;
- m_allocatedSpeedControllers = false;
- setSafetyEnabled(true);
- drive(0, 0);
- }
-
- /**
- * Drive the motors at "outputMagnitude" and "curve". Both outputMagnitude and curve are -1.0 to
- * +1.0 values, where 0.0 represents stopped and not turning. {@literal curve < 0 will turn left
- * and curve > 0} will turn right.
- *
- * <p>The algorithm for steering provides a constant turn radius for any normal speed range, both
- * forward and backward. Increasing sensitivity causes sharper turns for fixed values of curve.
- *
- * <p>This function will most likely be used in an autonomous routine.
- *
- * @param outputMagnitude The speed setting for the outside wheel in a turn, forward or backwards,
- * +1 to -1.
- * @param curve The rate of turn, constant for different forward speeds. Set {@literal
- * curve < 0 for left turn or curve > 0 for right turn.} Set curve =
- * e^(-r/w) to get a turn radius r for wheelbase w of your robot.
- * Conversely, turn radius r = -ln(curve)*w for a given value of curve and
- * wheelbase w.
- */
- public void drive(double outputMagnitude, double curve) {
- final double leftOutput;
- final double rightOutput;
-
- if (!kArcadeRatioCurve_Reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive_ArcadeRatioCurve,
- getNumMotors());
- kArcadeRatioCurve_Reported = true;
- }
- if (curve < 0) {
- double value = Math.log(-curve);
- double ratio = (value - m_sensitivity) / (value + m_sensitivity);
- if (ratio == 0) {
- ratio = 0.0000000001;
- }
- leftOutput = outputMagnitude / ratio;
- rightOutput = outputMagnitude;
- } else if (curve > 0) {
- double value = Math.log(curve);
- double ratio = (value - m_sensitivity) / (value + m_sensitivity);
- if (ratio == 0) {
- ratio = 0.0000000001;
- }
- leftOutput = outputMagnitude;
- rightOutput = outputMagnitude / ratio;
- } else {
- leftOutput = outputMagnitude;
- rightOutput = outputMagnitude;
- }
- setLeftRightMotorOutputs(leftOutput, rightOutput);
- }
-
- /**
- * Provide tank steering using the stored robot configuration. drive the robot using two joystick
- * inputs. The Y-axis will be selected from each Joystick object. The calculated values will be
- * squared to decrease sensitivity at low speeds.
- *
- * @param leftStick The joystick to control the left side of the robot.
- * @param rightStick The joystick to control the right side of the robot.
- */
- public void tankDrive(GenericHID leftStick, GenericHID rightStick) {
- requireNonNullParam(leftStick, "leftStick", "tankDrive");
- requireNonNullParam(rightStick, "rightStick", "tankDrive");
-
- tankDrive(leftStick.getY(), rightStick.getY(), true);
- }
-
- /**
- * Provide tank steering using the stored robot configuration. drive the robot using two joystick
- * inputs. The Y-axis will be selected from each Joystick object.
- *
- * @param leftStick The joystick to control the left side of the robot.
- * @param rightStick The joystick to control the right side of the robot.
- * @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
- */
- public void tankDrive(GenericHID leftStick, GenericHID rightStick, boolean squaredInputs) {
- requireNonNullParam(leftStick, "leftStick", "tankDrive");
- requireNonNullParam(rightStick, "rightStick", "tankDrive");
-
- tankDrive(leftStick.getY(), rightStick.getY(), squaredInputs);
- }
-
- /**
- * Provide tank steering using the stored robot configuration. This function lets you pick the
- * axis to be used on each Joystick object for the left and right sides of the robot. The
- * calculated values will be squared to decrease sensitivity at low speeds.
- *
- * @param leftStick The Joystick object to use for the left side of the robot.
- * @param leftAxis The axis to select on the left side Joystick object.
- * @param rightStick The Joystick object to use for the right side of the robot.
- * @param rightAxis The axis to select on the right side Joystick object.
- */
- public void tankDrive(GenericHID leftStick, final int leftAxis, GenericHID rightStick,
- final int rightAxis) {
- requireNonNullParam(leftStick, "leftStick", "tankDrive");
- requireNonNullParam(rightStick, "rightStick", "tankDrive");
-
- tankDrive(leftStick.getRawAxis(leftAxis), rightStick.getRawAxis(rightAxis), true);
- }
-
- /**
- * Provide tank steering using the stored robot configuration. This function lets you pick the
- * axis to be used on each Joystick object for the left and right sides of the robot.
- *
- * @param leftStick The Joystick object to use for the left side of the robot.
- * @param leftAxis The axis to select on the left side Joystick object.
- * @param rightStick The Joystick object to use for the right side of the robot.
- * @param rightAxis The axis to select on the right side Joystick object.
- * @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
- */
- public void tankDrive(GenericHID leftStick, final int leftAxis, GenericHID rightStick,
- final int rightAxis, boolean squaredInputs) {
- requireNonNullParam(leftStick, "leftStick", "tankDrive");
- requireNonNullParam(rightStick, "rightStick", "tankDrive");
-
- tankDrive(leftStick.getRawAxis(leftAxis), rightStick.getRawAxis(rightAxis), squaredInputs);
- }
-
- /**
- * Provide tank steering using the stored robot configuration. This function lets you directly
- * provide joystick values from any source.
- *
- * @param leftValue The value of the left stick.
- * @param rightValue The value of the right stick.
- * @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
- */
- public void tankDrive(double leftValue, double rightValue, boolean squaredInputs) {
- if (!kTank_Reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive_Tank,
- getNumMotors());
- kTank_Reported = true;
- }
-
- leftValue = limit(leftValue);
- rightValue = limit(rightValue);
-
- // square the inputs (while preserving the sign) to increase fine control
- // while permitting full power
- if (squaredInputs) {
- leftValue = Math.copySign(leftValue * leftValue, leftValue);
- rightValue = Math.copySign(rightValue * rightValue, rightValue);
- }
- setLeftRightMotorOutputs(leftValue, rightValue);
- }
-
- /**
- * Provide tank steering using the stored robot configuration. This function lets you directly
- * provide joystick values from any source. The calculated values will be squared to decrease
- * sensitivity at low speeds.
- *
- * @param leftValue The value of the left stick.
- * @param rightValue The value of the right stick.
- */
- public void tankDrive(double leftValue, double rightValue) {
- tankDrive(leftValue, rightValue, true);
- }
-
- /**
- * Arcade drive implements single stick driving. Given a single Joystick, the class assumes the Y
- * axis for the move value and the X axis for the rotate value. (Should add more information here
- * regarding the way that arcade drive works.)
- *
- * @param stick The joystick to use for Arcade single-stick driving. The Y-axis will be
- * selected for forwards/backwards and the X-axis will be selected for
- * rotation rate.
- * @param squaredInputs If true, the sensitivity will be decreased for small values
- */
- public void arcadeDrive(GenericHID stick, boolean squaredInputs) {
- // simply call the full-featured arcadeDrive with the appropriate values
- arcadeDrive(stick.getY(), stick.getX(), squaredInputs);
- }
-
- /**
- * Arcade drive implements single stick driving. Given a single Joystick, the class assumes the Y
- * axis for the move value and the X axis for the rotate value. (Should add more information here
- * regarding the way that arcade drive works.) The calculated values will be squared to decrease
- * sensitivity at low speeds.
- *
- * @param stick The joystick to use for Arcade single-stick driving. The Y-axis will be selected
- * for forwards/backwards and the X-axis will be selected for rotation rate.
- */
- public void arcadeDrive(GenericHID stick) {
- arcadeDrive(stick, true);
- }
-
- /**
- * Arcade drive implements single stick driving. Given two joystick instances and two axis,
- * compute the values to send to either two or four motors.
- *
- * @param moveStick The Joystick object that represents the forward/backward direction
- * @param moveAxis The axis on the moveStick object to use for forwards/backwards (typically
- * Y_AXIS)
- * @param rotateStick The Joystick object that represents the rotation value
- * @param rotateAxis The axis on the rotation object to use for the rotate right/left
- * (typically X_AXIS)
- * @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
- */
- public void arcadeDrive(GenericHID moveStick, final int moveAxis, GenericHID rotateStick,
- final int rotateAxis, boolean squaredInputs) {
- double moveValue = moveStick.getRawAxis(moveAxis);
- double rotateValue = rotateStick.getRawAxis(rotateAxis);
-
- arcadeDrive(moveValue, rotateValue, squaredInputs);
- }
-
- /**
- * Arcade drive implements single stick driving. Given two joystick instances and two axis,
- * compute the values to send to either two or four motors. The calculated values will be
- * squared to decrease sensitivity at low speeds.
- *
- * @param moveStick The Joystick object that represents the forward/backward direction
- * @param moveAxis The axis on the moveStick object to use for forwards/backwards (typically
- * Y_AXIS)
- * @param rotateStick The Joystick object that represents the rotation value
- * @param rotateAxis The axis on the rotation object to use for the rotate right/left (typically
- * X_AXIS)
- */
- public void arcadeDrive(GenericHID moveStick, final int moveAxis, GenericHID rotateStick,
- final int rotateAxis) {
- arcadeDrive(moveStick, moveAxis, rotateStick, rotateAxis, true);
- }
-
- /**
- * Arcade drive implements single stick driving. This function lets you directly provide
- * joystick values from any source.
- *
- * @param moveValue The value to use for forwards/backwards
- * @param rotateValue The value to use for the rotate right/left
- * @param squaredInputs If set, decreases the sensitivity at low speeds
- */
- public void arcadeDrive(double moveValue, double rotateValue, boolean squaredInputs) {
- // local variables to hold the computed PWM values for the motors
- if (!kArcadeStandard_Reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive_ArcadeStandard,
- getNumMotors());
- kArcadeStandard_Reported = true;
- }
-
- double leftMotorSpeed;
- double rightMotorSpeed;
-
- moveValue = limit(moveValue);
- rotateValue = limit(rotateValue);
-
- // square the inputs (while preserving the sign) to increase fine control
- // while permitting full power
- if (squaredInputs) {
- // square the inputs (while preserving the sign) to increase fine control
- // while permitting full power
- moveValue = Math.copySign(moveValue * moveValue, moveValue);
- rotateValue = Math.copySign(rotateValue * rotateValue, rotateValue);
- }
-
- if (moveValue > 0.0) {
- if (rotateValue > 0.0) {
- leftMotorSpeed = moveValue - rotateValue;
- rightMotorSpeed = Math.max(moveValue, rotateValue);
- } else {
- leftMotorSpeed = Math.max(moveValue, -rotateValue);
- rightMotorSpeed = moveValue + rotateValue;
- }
- } else {
- if (rotateValue > 0.0) {
- leftMotorSpeed = -Math.max(-moveValue, rotateValue);
- rightMotorSpeed = moveValue + rotateValue;
- } else {
- leftMotorSpeed = moveValue - rotateValue;
- rightMotorSpeed = -Math.max(-moveValue, -rotateValue);
- }
- }
-
- setLeftRightMotorOutputs(leftMotorSpeed, rightMotorSpeed);
- }
-
- /**
- * Arcade drive implements single stick driving. This function lets you directly provide
- * joystick values from any source. The calculated values will be squared to decrease
- * sensitivity at low speeds.
- *
- * @param moveValue The value to use for forwards/backwards
- * @param rotateValue The value to use for the rotate right/left
- */
- public void arcadeDrive(double moveValue, double rotateValue) {
- arcadeDrive(moveValue, rotateValue, true);
- }
-
- /**
- * Drive method for Mecanum wheeled robots.
- *
- * <p>A method for driving with Mecanum wheeled robots. There are 4 wheels on the robot, arranged
- * so that the front and back wheels are toed in 45 degrees. When looking at the wheels from the
- * top, the roller axles should form an X across the robot.
- *
- * <p>This is designed to be directly driven by joystick axes.
- *
- * @param x The speed that the robot should drive in the X direction. [-1.0..1.0]
- * @param y The speed that the robot should drive in the Y direction. This input is
- * inverted to match the forward == -1.0 that joysticks produce. [-1.0..1.0]
- * @param rotation The rate of rotation for the robot that is completely independent of the
- * translation. [-1.0..1.0]
- * @param gyroAngle The current angle reading from the gyro. Use this to implement field-oriented
- * controls.
- */
- @SuppressWarnings("ParameterName")
- public void mecanumDrive_Cartesian(double x, double y, double rotation, double gyroAngle) {
- if (!kMecanumCartesian_Reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive_MecanumCartesian,
- getNumMotors());
- kMecanumCartesian_Reported = true;
- }
- @SuppressWarnings("LocalVariableName")
- double xIn = x;
- @SuppressWarnings("LocalVariableName")
- double yIn = y;
- // Negate y for the joystick.
- yIn = -yIn;
- // Compensate for gyro angle.
- double[] rotated = rotateVector(xIn, yIn, gyroAngle);
- xIn = rotated[0];
- yIn = rotated[1];
-
- double[] wheelSpeeds = new double[kMaxNumberOfMotors];
- wheelSpeeds[MotorType.kFrontLeft.value] = xIn + yIn + rotation;
- wheelSpeeds[MotorType.kFrontRight.value] = -xIn + yIn - rotation;
- wheelSpeeds[MotorType.kRearLeft.value] = -xIn + yIn + rotation;
- wheelSpeeds[MotorType.kRearRight.value] = xIn + yIn - rotation;
-
- normalize(wheelSpeeds);
- m_frontLeftMotor.set(wheelSpeeds[MotorType.kFrontLeft.value] * m_maxOutput);
- m_frontRightMotor.set(wheelSpeeds[MotorType.kFrontRight.value] * m_maxOutput);
- m_rearLeftMotor.set(wheelSpeeds[MotorType.kRearLeft.value] * m_maxOutput);
- m_rearRightMotor.set(wheelSpeeds[MotorType.kRearRight.value] * m_maxOutput);
-
- feed();
- }
-
- /**
- * Drive method for Mecanum wheeled robots.
- *
- * <p>A method for driving with Mecanum wheeled robots. There are 4 wheels on the robot, arranged
- * so that the front and back wheels are toed in 45 degrees. When looking at the wheels from the
- * top, the roller axles should form an X across the robot.
- *
- * @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0]
- * @param direction The angle the robot should drive in degrees. The direction and magnitude
- * are independent of the rotation rate. [-180.0..180.0]
- * @param rotation The rate of rotation for the robot that is completely independent of the
- * magnitude or direction. [-1.0..1.0]
- */
- public void mecanumDrive_Polar(double magnitude, double direction, double rotation) {
- if (!kMecanumPolar_Reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive_MecanumPolar,
- getNumMotors());
- kMecanumPolar_Reported = true;
- }
- // Normalized for full power along the Cartesian axes.
- magnitude = limit(magnitude) * Math.sqrt(2.0);
- // The rollers are at 45 degree angles.
- double dirInRad = (direction + 45.0) * Math.PI / 180.0;
- double cosD = Math.cos(dirInRad);
- double sinD = Math.sin(dirInRad);
-
- double[] wheelSpeeds = new double[kMaxNumberOfMotors];
- wheelSpeeds[MotorType.kFrontLeft.value] = sinD * magnitude + rotation;
- wheelSpeeds[MotorType.kFrontRight.value] = cosD * magnitude - rotation;
- wheelSpeeds[MotorType.kRearLeft.value] = cosD * magnitude + rotation;
- wheelSpeeds[MotorType.kRearRight.value] = sinD * magnitude - rotation;
-
- normalize(wheelSpeeds);
-
- m_frontLeftMotor.set(wheelSpeeds[MotorType.kFrontLeft.value] * m_maxOutput);
- m_frontRightMotor.set(wheelSpeeds[MotorType.kFrontRight.value] * m_maxOutput);
- m_rearLeftMotor.set(wheelSpeeds[MotorType.kRearLeft.value] * m_maxOutput);
- m_rearRightMotor.set(wheelSpeeds[MotorType.kRearRight.value] * m_maxOutput);
-
- feed();
- }
-
- /**
- * Holonomic Drive method for Mecanum wheeled robots.
- *
- * <p>This is an alias to mecanumDrive_Polar() for backward compatibility
- *
- * @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0]
- * @param direction The direction the robot should drive. The direction and maginitude are
- * independent of the rotation rate.
- * @param rotation The rate of rotation for the robot that is completely independent of the
- * magnitute or direction. [-1.0..1.0]
- */
- void holonomicDrive(double magnitude, double direction, double rotation) {
- mecanumDrive_Polar(magnitude, direction, rotation);
- }
-
- /**
- * Set the speed of the right and left motors. This is used once an appropriate drive setup
- * function is called such as twoWheelDrive(). The motors are set to "leftSpeed" and
- * "rightSpeed" and includes flipping the direction of one side for opposing motors.
- *
- * @param leftOutput The speed to send to the left side of the robot.
- * @param rightOutput The speed to send to the right side of the robot.
- */
- public void setLeftRightMotorOutputs(double leftOutput, double rightOutput) {
-
- if (m_frontLeftMotor != null) {
- m_frontLeftMotor.set(limit(leftOutput) * m_maxOutput);
- }
- m_rearLeftMotor.set(limit(leftOutput) * m_maxOutput);
-
- if (m_frontRightMotor != null) {
- m_frontRightMotor.set(-limit(rightOutput) * m_maxOutput);
- }
- m_rearRightMotor.set(-limit(rightOutput) * m_maxOutput);
-
- feed();
- }
-
- /**
- * Limit motor values to the -1.0 to +1.0 range.
- */
- protected static double limit(double number) {
- if (number > 1.0) {
- return 1.0;
- }
- if (number < -1.0) {
- return -1.0;
- }
- return number;
- }
-
- /**
- * Normalize all wheel speeds if the magnitude of any wheel is greater than 1.0.
- */
- protected static void normalize(double[] wheelSpeeds) {
- double maxMagnitude = Math.abs(wheelSpeeds[0]);
- for (int i = 1; i < kMaxNumberOfMotors; i++) {
- double temp = Math.abs(wheelSpeeds[i]);
- if (maxMagnitude < temp) {
- maxMagnitude = temp;
- }
- }
- if (maxMagnitude > 1.0) {
- for (int i = 0; i < kMaxNumberOfMotors; i++) {
- wheelSpeeds[i] = wheelSpeeds[i] / maxMagnitude;
- }
- }
- }
-
- /**
- * Rotate a vector in Cartesian space.
- */
- @SuppressWarnings("ParameterName")
- protected static double[] rotateVector(double x, double y, double angle) {
- double cosA = Math.cos(angle * (Math.PI / 180.0));
- double sinA = Math.sin(angle * (Math.PI / 180.0));
- double[] out = new double[2];
- out[0] = x * cosA - y * sinA;
- out[1] = x * sinA + y * cosA;
- return out;
- }
-
- /**
- * Invert a motor direction. This is used when a motor should run in the opposite direction as the
- * drive code would normally run it. Motors that are direct drive would be inverted, the drive
- * code assumes that the motors are geared with one reversal.
- *
- * @param motor The motor index to invert.
- * @param isInverted True if the motor should be inverted when operated.
- */
- public void setInvertedMotor(MotorType motor, boolean isInverted) {
- switch (motor) {
- case kFrontLeft:
- m_frontLeftMotor.setInverted(isInverted);
- break;
- case kFrontRight:
- m_frontRightMotor.setInverted(isInverted);
- break;
- case kRearLeft:
- m_rearLeftMotor.setInverted(isInverted);
- break;
- case kRearRight:
- m_rearRightMotor.setInverted(isInverted);
- break;
- default:
- throw new IllegalArgumentException("Illegal motor type: " + motor);
- }
- }
-
- /**
- * Set the turning sensitivity.
- *
- * <p>This only impacts the drive() entry-point.
- *
- * @param sensitivity Effectively sets the turning sensitivity (or turn radius for a given value)
- */
- public void setSensitivity(double sensitivity) {
- m_sensitivity = sensitivity;
- }
-
- /**
- * Configure the scaling factor for using RobotDrive with motor controllers in a mode other than
- * PercentVbus.
- *
- * @param maxOutput Multiplied with the output percentage computed by the drive functions.
- */
- public void setMaxOutput(double maxOutput) {
- m_maxOutput = maxOutput;
- }
-
- /**
- * Free the speed controllers if they were allocated locally.
- */
- @Override
- public void close() {
- if (m_allocatedSpeedControllers) {
- if (m_frontLeftMotor != null) {
- ((PWM) m_frontLeftMotor).close();
- }
- if (m_frontRightMotor != null) {
- ((PWM) m_frontRightMotor).close();
- }
- if (m_rearLeftMotor != null) {
- ((PWM) m_rearLeftMotor).close();
- }
- if (m_rearRightMotor != null) {
- ((PWM) m_rearRightMotor).close();
- }
- }
- }
-
- @Override
- public String getDescription() {
- return "Robot Drive";
- }
-
- @Override
- public void stopMotor() {
- if (m_frontLeftMotor != null) {
- m_frontLeftMotor.stopMotor();
- }
- if (m_frontRightMotor != null) {
- m_frontRightMotor.stopMotor();
- }
- if (m_rearLeftMotor != null) {
- m_rearLeftMotor.stopMotor();
- }
- if (m_rearRightMotor != null) {
- m_rearRightMotor.stopMotor();
- }
-
- feed();
- }
-
- protected int getNumMotors() {
- int motors = 0;
- if (m_frontLeftMotor != null) {
- motors++;
- }
- if (m_frontRightMotor != null) {
- motors++;
- }
- if (m_rearLeftMotor != null) {
- motors++;
- }
- if (m_rearRightMotor != null) {
- motors++;
- }
- return motors;
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotState.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotState.java
index 58004d5..462051a 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotState.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotState.java
@@ -1,38 +1,39 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-@SuppressWarnings("JavadocMethod")
+@SuppressWarnings("MissingJavadocMethod")
public final class RobotState {
public static boolean isDisabled() {
- return DriverStation.getInstance().isDisabled();
+ return DriverStation.isDisabled();
}
public static boolean isEnabled() {
- return DriverStation.getInstance().isEnabled();
+ return DriverStation.isEnabled();
}
public static boolean isEStopped() {
- return DriverStation.getInstance().isEStopped();
+ return DriverStation.isEStopped();
}
+ @Deprecated
public static boolean isOperatorControl() {
- return DriverStation.getInstance().isOperatorControl();
+ return isTeleop();
+ }
+
+ public static boolean isTeleop() {
+ return DriverStation.isTeleop();
}
public static boolean isAutonomous() {
- return DriverStation.getInstance().isAutonomous();
+ return DriverStation.isAutonomous();
}
public static boolean isTest() {
- return DriverStation.getInstance().isTest();
+ return DriverStation.isTest();
}
- private RobotState() {
- }
+ private RobotState() {}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RuntimeType.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RuntimeType.java
new file mode 100644
index 0000000..e7af118
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RuntimeType.java
@@ -0,0 +1,34 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import edu.wpi.first.hal.HALUtil;
+
+public enum RuntimeType {
+ kRoboRIO(HALUtil.RUNTIME_ROBORIO),
+ kRoboRIO2(HALUtil.RUNTIME_ROBORIO2),
+ kSimulation(HALUtil.RUNTIME_SIMULATION);
+
+ public final int value;
+
+ RuntimeType(int value) {
+ this.value = value;
+ }
+
+ /**
+ * Construct a runtime type from an int value.
+ *
+ * @param type Runtime type as int
+ * @return Matching runtime type
+ */
+ public static RuntimeType getValue(int type) {
+ if (type == HALUtil.RUNTIME_ROBORIO) {
+ return RuntimeType.kRoboRIO;
+ } else if (type == HALUtil.RUNTIME_ROBORIO2) {
+ return RuntimeType.kRoboRIO2;
+ }
+ return RuntimeType.kSimulation;
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SD540.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SD540.java
deleted file mode 100644
index b2e98b6..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SD540.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Mindsensors SD540 Speed Controller.
- *
- * <p>Note that the SD540 uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the SD540 User Manual
- * available from Mindsensors.
- *
- * <p><ul>
- * <li>2.05ms = full "forward"
- * <li>1.55ms = the "high end" of the deadband range
- * <li>1.50ms = center of the deadband range (off)
- * <li>1.44ms = the "low end" of the deadband range
- * <li>0.94ms = full "reverse"
- * </ul>
- */
-public class SD540 extends PWMSpeedController {
- /**
- * Common initialization code called by all constructors.
- */
- protected void initSD540() {
- setBounds(2.05, 1.55, 1.50, 1.44, 0.94);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_MindsensorsSD540, getChannel() + 1);
- SendableRegistry.setName(this, "SD540", getChannel());
- }
-
- /**
- * Constructor.
- *
- * @param channel The PWM channel that the SD540 is attached to. 0-9 are on-board, 10-19 are on
- * the MXP port
- */
- public SD540(final int channel) {
- super(channel);
- initSD540();
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java
index aa3c679..2243140 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java
@@ -1,30 +1,26 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.IntBuffer;
-
import edu.wpi.first.hal.AccumulatorResult;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SPIJNI;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
-/**
- * Represents a SPI bus port.
- */
-@SuppressWarnings("PMD.CyclomaticComplexity")
+/** Represents a SPI bus port. */
public class SPI implements AutoCloseable {
public enum Port {
- kOnboardCS0(0), kOnboardCS1(1), kOnboardCS2(2), kOnboardCS3(3), kMXP(4);
+ kOnboardCS0(0),
+ kOnboardCS1(1),
+ kOnboardCS2(2),
+ kOnboardCS3(3),
+ kMXP(4);
- @SuppressWarnings("MemberName")
public final int value;
Port(int value) {
@@ -50,6 +46,10 @@
HAL.report(tResourceType.kResourceType_SPI, port.value + 1);
}
+ public int getPort() {
+ return m_port;
+ }
+
@Override
public void close() {
if (m_accum != null) {
@@ -126,6 +126,7 @@
/**
* Configure that the data is stable on the falling edge and the data changes on the rising edge.
* Note this gets reversed is setClockActiveLow is set.
+ *
* @deprecated use {@link #setSampleDataOnTrailingEdge()} in most cases.
*/
@Deprecated
@@ -137,6 +138,7 @@
/**
* Configure that the data is stable on the rising edge and the data changes on the falling edge.
* Note this gets reversed is setClockActiveLow is set.
+ *
* @deprecated use {@link #setSampleDataOnLeadingEdge()} in most cases.
*/
@Deprecated
@@ -145,18 +147,12 @@
SPIJNI.spiSetOpts(m_port, m_msbFirst, m_sampleOnTrailing, m_clockIdleHigh);
}
-
-
- /**
- * Configure the chip select line to be active high.
- */
+ /** Configure the chip select line to be active high. */
public final void setChipSelectActiveHigh() {
SPIJNI.spiSetChipSelectActiveHigh(m_port);
}
- /**
- * Configure the chip select line to be active low.
- */
+ /** Configure the chip select line to be active low. */
public final void setChipSelectActiveLow() {
SPIJNI.spiSetChipSelectActiveLow(m_port);
}
@@ -166,6 +162,10 @@
*
* <p>If not running in output only mode, also saves the data received on the CIPO input during
* the transfer into the receive FIFO.
+ *
+ * @param dataToSend The buffer containing the data to send.
+ * @param size The number of bytes to send.
+ * @return Number of bytes written or -1 on error.
*/
public int write(byte[] dataToSend, int size) {
if (dataToSend.length < size) {
@@ -181,6 +181,8 @@
* the transfer into the receive FIFO.
*
* @param dataToSend The buffer containing the data to send.
+ * @param size The number of bytes to send.
+ * @return Number of bytes written or -1 on error.
*/
@SuppressWarnings("ByteBufferBackingArray")
public int write(ByteBuffer dataToSend, int size) {
@@ -204,8 +206,11 @@
* <p>If the receive FIFO is empty, there is no active transfer, and initiate is false, errors.
*
* @param initiate If true, this function pushes "0" into the transmit buffer and initiates a
- * transfer. If false, this function assumes that data is already in the receive
- * FIFO from a previous write.
+ * transfer. If false, this function assumes that data is already in the receive FIFO from a
+ * previous write.
+ * @param dataReceived Buffer in which to store bytes read.
+ * @param size Number of bytes to read.
+ * @return Number of bytes read or -1 on error.
*/
public int read(boolean initiate, byte[] dataReceived, int size) {
if (dataReceived.length < size) {
@@ -221,11 +226,12 @@
*
* <p>If the receive FIFO is empty, there is no active transfer, and initiate is false, errors.
*
- * @param initiate If true, this function pushes "0" into the transmit buffer and initiates
- * a transfer. If false, this function assumes that data is already in the
- * receive FIFO from a previous write.
+ * @param initiate If true, this function pushes "0" into the transmit buffer and initiates a
+ * transfer. If false, this function assumes that data is already in the receive FIFO from a
+ * previous write.
* @param dataReceived The buffer to be filled with the received data.
- * @param size The length of the transaction, in bytes
+ * @param size The length of the transaction, in bytes
+ * @return Number of bytes read or -1 on error.
*/
@SuppressWarnings("ByteBufferBackingArray")
public int read(boolean initiate, ByteBuffer dataReceived, int size) {
@@ -244,9 +250,10 @@
/**
* Perform a simultaneous read/write transaction with the device.
*
- * @param dataToSend The data to be written out to the device
+ * @param dataToSend The data to be written out to the device
* @param dataReceived Buffer to receive data from the device
- * @param size The length of the transaction, in bytes
+ * @param size The length of the transaction, in bytes
+ * @return TODO
*/
public int transaction(byte[] dataToSend, byte[] dataReceived, int size) {
if (dataToSend.length < size) {
@@ -261,11 +268,12 @@
/**
* Perform a simultaneous read/write transaction with the device.
*
- * @param dataToSend The data to be written out to the device.
+ * @param dataToSend The data to be written out to the device.
* @param dataReceived Buffer to receive data from the device.
- * @param size The length of the transaction, in bytes
+ * @param size The length of the transaction, in bytes
+ * @return TODO
*/
- @SuppressWarnings({"PMD.CyclomaticComplexity", "ByteBufferBackingArray"})
+ @SuppressWarnings("ByteBufferBackingArray")
public int transaction(ByteBuffer dataToSend, ByteBuffer dataReceived, int size) {
if (dataToSend.hasArray() && dataReceived.hasArray()) {
return transaction(dataToSend.array(), dataReceived.array(), size);
@@ -288,8 +296,8 @@
/**
* Initialize automatic SPI transfer engine.
*
- * <p>Only a single engine is available, and use of it blocks use of all other
- * chip select usage on the same physical SPI port while it is running.
+ * <p>Only a single engine is available, and use of it blocks use of all other chip select usage
+ * on the same physical SPI port while it is running.
*
* @param bufferSize buffer size in bytes
*/
@@ -297,9 +305,7 @@
SPIJNI.spiInitAuto(m_port, bufferSize);
}
- /**
- * Frees the automatic SPI transfer engine.
- */
+ /** Frees the automatic SPI transfer engine. */
public void freeAuto() {
SPIJNI.spiFreeAuto(m_port);
}
@@ -307,8 +313,7 @@
/**
* Set the data to be transmitted by the engine.
*
- * <p>Up to 16 bytes are configurable, and may be followed by up to 127 zero
- * bytes.
+ * <p>Up to 16 bytes are configurable, and may be followed by up to 127 zero bytes.
*
* @param dataToSend data to send (maximum 16 bytes)
* @param zeroSize number of zeros to send after the data
@@ -320,8 +325,8 @@
/**
* Start running the automatic SPI transfer engine at a periodic rate.
*
- * <p>{@link #initAuto(int)} and {@link #setAutoTransmitData(byte[], int)} must
- * be called before calling this function.
+ * <p>{@link #initAuto(int)} and {@link #setAutoTransmitData(byte[], int)} must be called before
+ * calling this function.
*
* @param period period between transfers, in seconds (us resolution)
*/
@@ -332,28 +337,28 @@
/**
* Start running the automatic SPI transfer engine when a trigger occurs.
*
- * <p>{@link #initAuto(int)} and {@link #setAutoTransmitData(byte[], int)} must
- * be called before calling this function.
+ * <p>{@link #initAuto(int)} and {@link #setAutoTransmitData(byte[], int)} must be called before
+ * calling this function.
*
* @param source digital source for the trigger (may be an analog trigger)
* @param rising trigger on the rising edge
* @param falling trigger on the falling edge
*/
public void startAutoTrigger(DigitalSource source, boolean rising, boolean falling) {
- SPIJNI.spiStartAutoTrigger(m_port, source.getPortHandleForRouting(),
- source.getAnalogTriggerTypeForRouting(), rising, falling);
+ SPIJNI.spiStartAutoTrigger(
+ m_port,
+ source.getPortHandleForRouting(),
+ source.getAnalogTriggerTypeForRouting(),
+ rising,
+ falling);
}
- /**
- * Stop running the automatic SPI transfer engine.
- */
+ /** Stop running the automatic SPI transfer engine. */
public void stopAuto() {
SPIJNI.spiStopAuto(m_port);
}
- /**
- * Force the engine to make a single transfer.
- */
+ /** Force the engine to make a single transfer. */
public void forceAutoRead() {
SPIJNI.spiForceAutoRead(m_port);
}
@@ -361,16 +366,15 @@
/**
* Read data that has been transferred by the automatic SPI transfer engine.
*
- * <p>Transfers may be made a byte at a time, so it's necessary for the caller
- * to handle cases where an entire transfer has not been completed.
+ * <p>Transfers may be made a byte at a time, so it's necessary for the caller to handle cases
+ * where an entire transfer has not been completed.
*
- * <p>Each received data sequence consists of a timestamp followed by the
- * received data bytes, one byte per word (in the least significant byte).
- * The length of each received data sequence is the same as the combined
- * size of the data and zeroSize set in setAutoTransmitData().
+ * <p>Each received data sequence consists of a timestamp followed by the received data bytes, one
+ * byte per word (in the least significant byte). The length of each received data sequence is the
+ * same as the combined size of the data and zeroSize set in setAutoTransmitData().
*
- * <p>Blocks until numToRead words have been read or timeout expires.
- * May be called with numToRead=0 to retrieve how many words are available.
+ * <p>Blocks until numToRead words have been read or timeout expires. May be called with
+ * numToRead=0 to retrieve how many words are available.
*
* @param buffer buffer where read words are stored
* @param numToRead number of words to read
@@ -382,8 +386,8 @@
throw new IllegalArgumentException("must be a direct buffer");
}
if (buffer.capacity() < numToRead * 4) {
- throw new IllegalArgumentException("buffer is too small, must be at least "
- + (numToRead * 4));
+ throw new IllegalArgumentException(
+ "buffer is too small, must be at least " + (numToRead * 4));
}
return SPIJNI.spiReadAutoReceivedData(m_port, buffer, numToRead, timeout);
}
@@ -391,16 +395,15 @@
/**
* Read data that has been transferred by the automatic SPI transfer engine.
*
- * <p>Transfers may be made a byte at a time, so it's necessary for the caller
- * to handle cases where an entire transfer has not been completed.
+ * <p>Transfers may be made a byte at a time, so it's necessary for the caller to handle cases
+ * where an entire transfer has not been completed.
*
- * <p>Each received data sequence consists of a timestamp followed by the
- * received data bytes, one byte per word (in the least significant byte).
- * The length of each received data sequence is the same as the combined
- * size of the data and zeroSize set in setAutoTransmitData().
+ * <p>Each received data sequence consists of a timestamp followed by the received data bytes, one
+ * byte per word (in the least significant byte). The length of each received data sequence is the
+ * same as the combined size of the data and zeroSize set in setAutoTransmitData().
*
- * <p>Blocks until numToRead words have been read or timeout expires.
- * May be called with numToRead=0 to retrieve how many words are available.
+ * <p>Blocks until numToRead words have been read or timeout expires. May be called with
+ * numToRead=0 to retrieve how many words are available.
*
* @param buffer array where read words are stored
* @param numToRead number of words to read
@@ -415,8 +418,8 @@
}
/**
- * Get the number of bytes dropped by the automatic SPI transfer engine due
- * to the receive buffer being full.
+ * Get the number of bytes dropped by the automatic SPI transfer engine due to the receive buffer
+ * being full.
*
* @return Number of bytes dropped
*/
@@ -437,15 +440,22 @@
private static final int kAccumulateDepth = 2048;
- @SuppressWarnings("PMD.TooManyFields")
private static class Accumulator implements AutoCloseable {
- Accumulator(int port, int xferSize, int validMask, int validValue, int dataShift,
- int dataSize, boolean isSigned, boolean bigEndian) {
+ Accumulator(
+ int port,
+ int xferSize,
+ int validMask,
+ int validValue,
+ int dataShift,
+ int dataSize,
+ boolean isSigned,
+ boolean bigEndian) {
m_notifier = new Notifier(this::update);
- m_buf = ByteBuffer.allocateDirect((xferSize + 1) * kAccumulateDepth * 4)
- .order(ByteOrder.nativeOrder());
+ m_buf =
+ ByteBuffer.allocateDirect((xferSize + 1) * kAccumulateDepth * 4)
+ .order(ByteOrder.nativeOrder());
m_intBuf = m_buf.asIntBuffer();
- m_xferSize = xferSize + 1; // +1 for timestamp
+ m_xferSize = xferSize + 1; // +1 for timestamp
m_validMask = validMask;
m_validValue = validValue;
m_dataShift = dataShift;
@@ -478,15 +488,14 @@
final int m_validMask;
final int m_validValue;
- final int m_dataMax; // one more than max data value
- final int m_dataMsbMask; // data field MSB mask (for signed)
- final int m_dataShift; // data field shift right amount, in bits
- final int m_xferSize; // SPI transfer size, in bytes
- final boolean m_isSigned; // is data field signed?
- final boolean m_bigEndian; // is response big endian?
+ final int m_dataMax; // one more than max data value
+ final int m_dataMsbMask; // data field MSB mask (for signed)
+ final int m_dataShift; // data field shift right amount, in bits
+ final int m_xferSize; // SPI transfer size, in bytes
+ final boolean m_isSigned; // is data field signed?
+ final boolean m_bigEndian; // is response big endian?
final int m_port;
- @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
void update() {
synchronized (m_mutex) {
boolean done = false;
@@ -503,7 +512,7 @@
done = false;
}
if (numToRead == 0) {
- return; // no samples
+ return; // no samples
}
// read buffered data
@@ -546,11 +555,12 @@
if (m_count != 0) {
// timestamps use the 1us FPGA clock; also handle rollover
if (timestamp >= m_lastTimestamp) {
- m_integratedValue += dataNoCenter * (timestamp - m_lastTimestamp)
- * 1e-6 - m_integratedCenter;
+ m_integratedValue +=
+ dataNoCenter * (timestamp - m_lastTimestamp) * 1e-6 - m_integratedCenter;
} else {
- m_integratedValue += dataNoCenter * ((1L << 32) - m_lastTimestamp + timestamp)
- * 1e-6 - m_integratedCenter;
+ m_integratedValue +=
+ dataNoCenter * ((1L << 32) - m_lastTimestamp + timestamp) * 1e-6
+ - m_integratedCenter;
}
}
}
@@ -572,20 +582,26 @@
/**
* Initialize the accumulator.
*
- * @param period Time between reads
- * @param cmd SPI command to send to request data
- * @param xferSize SPI transfer size, in bytes
- * @param validMask Mask to apply to received data for validity checking
+ * @param period Time between reads
+ * @param cmd SPI command to send to request data
+ * @param xferSize SPI transfer size, in bytes
+ * @param validMask Mask to apply to received data for validity checking
* @param validValue After validMask is applied, required matching value for validity checking
- * @param dataShift Bit shift to apply to received data to get actual data value
- * @param dataSize Size (in bits) of data field
- * @param isSigned Is data field signed?
- * @param bigEndian Is device big endian?
+ * @param dataShift Bit shift to apply to received data to get actual data value
+ * @param dataSize Size (in bits) of data field
+ * @param isSigned Is data field signed?
+ * @param bigEndian Is device big endian?
*/
- public void initAccumulator(double period, int cmd, int xferSize,
- int validMask, int validValue,
- int dataShift, int dataSize,
- boolean isSigned, boolean bigEndian) {
+ public void initAccumulator(
+ double period,
+ int cmd,
+ int xferSize,
+ int validMask,
+ int validValue,
+ int dataShift,
+ int dataSize,
+ boolean isSigned,
+ boolean bigEndian) {
initAuto(xferSize * 2048);
byte[] cmdBytes = new byte[] {0, 0, 0, 0};
if (bigEndian) {
@@ -605,14 +621,13 @@
setAutoTransmitData(cmdBytes, xferSize - 4);
startAutoRate(period);
- m_accum = new Accumulator(m_port, xferSize, validMask, validValue, dataShift, dataSize,
- isSigned, bigEndian);
+ m_accum =
+ new Accumulator(
+ m_port, xferSize, validMask, validValue, dataShift, dataSize, isSigned, bigEndian);
m_accum.m_notifier.startPeriodic(period * 1024);
}
- /**
- * Frees the accumulator.
- */
+ /** Frees the accumulator. */
public void freeAccumulator() {
if (m_accum != null) {
m_accum.close();
@@ -621,9 +636,7 @@
freeAuto();
}
- /**
- * Resets the accumulator to zero.
- */
+ /** Resets the accumulator to zero. */
public void resetAccumulator() {
if (m_accum == null) {
return;
@@ -643,6 +656,8 @@
* <p>The center value is subtracted from each value before it is added to the accumulator. This
* is used for the center value of devices like gyros and accelerometers to make integration work
* and to take the device offset into account when integrating.
+ *
+ * @param center The accumulator's center value.
*/
public void setAccumulatorCenter(int center) {
if (m_accum == null) {
@@ -655,6 +670,8 @@
/**
* Set the accumulator's deadband.
+ *
+ * @param deadband The accumulator's deadband.
*/
public void setAccumulatorDeadband(int deadband) {
if (m_accum == null) {
@@ -667,6 +684,8 @@
/**
* Read the last value read by the accumulator engine.
+ *
+ * @return The last value read by the accumulator engine.
*/
public int getAccumulatorLastValue() {
if (m_accum == null) {
@@ -754,9 +773,11 @@
/**
* Set the center value of the accumulator integrator.
*
- * <p>The center value is subtracted from each value*dt before it is added to the
- * integrated value. This is used for the center value of devices like gyros
- * and accelerometers to take the device offset into account when integrating.
+ * <p>The center value is subtracted from each value*dt before it is added to the integrated
+ * value. This is used for the center value of devices like gyros and accelerometers to take the
+ * device offset into account when integrating.
+ *
+ * @param center The accumulator integrator's center value.
*/
public void setAccumulatorIntegratedCenter(double center) {
if (m_accum == null) {
@@ -768,8 +789,7 @@
}
/**
- * Read the integrated value. This is the sum of (each value * time between
- * values).
+ * Read the integrated value. This is the sum of (each value * time between values).
*
* @return The integrated value accumulated since the last Reset().
*/
@@ -784,11 +804,10 @@
}
/**
- * Read the average of the integrated value. This is the sum of (each value
- * times the time between values), divided by the count.
+ * Read the average of the integrated value. This is the sum of (each value times the time between
+ * values), divided by the count.
*
- * @return The average of the integrated value accumulated since the last
- * Reset().
+ * @return The average of the integrated value accumulated since the last Reset().
*/
public double getAccumulatorIntegratedAverage() {
if (m_accum == null) {
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Sendable.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Sendable.java
deleted file mode 100644
index 138f7f4..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Sendable.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-
-/**
- * The base interface for objects that can be sent over the network through network tables.
- */
-public interface Sendable {
- /**
- * Gets the name of this {@link Sendable} object.
- *
- * @return Name
- * @deprecated Use SendableRegistry.getName()
- */
- @Deprecated(since = "2020", forRemoval = true)
- default String getName() {
- return SendableRegistry.getName(this);
- }
-
- /**
- * Sets the name of this {@link Sendable} object.
- *
- * @param name name
- * @deprecated Use SendableRegistry.setName()
- */
- @Deprecated(since = "2020", forRemoval = true)
- default void setName(String name) {
- SendableRegistry.setName(this, name);
- }
-
- /**
- * Sets both the subsystem name and device name of this {@link Sendable} object.
- *
- * @param subsystem subsystem name
- * @param name device name
- * @deprecated Use SendableRegistry.setName()
- */
- @Deprecated(since = "2020", forRemoval = true)
- default void setName(String subsystem, String name) {
- SendableRegistry.setName(this, subsystem, name);
- }
-
- /**
- * Sets the name of the sensor with a channel number.
- *
- * @param moduleType A string that defines the module name in the label for the value
- * @param channel The channel number the device is plugged into
- * @deprecated Use SendableRegistry.setName()
- */
- @Deprecated(since = "2020", forRemoval = true)
- default void setName(String moduleType, int channel) {
- SendableRegistry.setName(this, moduleType, channel);
- }
-
- /**
- * Sets the name of the sensor with a module and channel number.
- *
- * @param moduleType A string that defines the module name in the label for the value
- * @param moduleNumber The number of the particular module type
- * @param channel The channel number the device is plugged into (usually PWM)
- * @deprecated Use SendableRegistry.setName()
- */
- @Deprecated(since = "2020", forRemoval = true)
- default void setName(String moduleType, int moduleNumber, int channel) {
- SendableRegistry.setName(this, moduleType, moduleNumber, channel);
- }
-
- /**
- * Gets the subsystem name of this {@link Sendable} object.
- *
- * @return Subsystem name
- * @deprecated Use SendableRegistry.getSubsystem()
- */
- @Deprecated(since = "2020", forRemoval = true)
- default String getSubsystem() {
- return SendableRegistry.getSubsystem(this);
- }
-
- /**
- * Sets the subsystem name of this {@link Sendable} object.
- *
- * @param subsystem subsystem name
- * @deprecated Use SendableRegistry.setSubsystem()
- */
- @Deprecated(since = "2020", forRemoval = true)
- default void setSubsystem(String subsystem) {
- SendableRegistry.setSubsystem(this, subsystem);
- }
-
- /**
- * Add a child component.
- *
- * @param child child component
- * @deprecated Use SendableRegistry.addChild()
- */
- @Deprecated(since = "2020", forRemoval = true)
- default void addChild(Object child) {
- SendableRegistry.addChild(this, child);
- }
-
- /**
- * Initializes this {@link Sendable} object.
- *
- * @param builder sendable builder
- */
- void initSendable(SendableBuilder builder);
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SendableBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SendableBase.java
deleted file mode 100644
index 4e2116c..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SendableBase.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Base class for all sensors. Stores most recent status information as well as containing utility
- * functions for checking channels and error processing.
- * @deprecated Use Sendable and SendableRegistry
- */
-@Deprecated(since = "2020", forRemoval = true)
-public abstract class SendableBase implements Sendable, AutoCloseable {
- /**
- * Creates an instance of the sensor base.
- */
- public SendableBase() {
- this(true);
- }
-
- /**
- * Creates an instance of the sensor base.
- *
- * @param addLiveWindow if true, add this Sendable to LiveWindow
- */
- public SendableBase(boolean addLiveWindow) {
- if (addLiveWindow) {
- SendableRegistry.addLW(this, "");
- } else {
- SendableRegistry.add(this, "");
- }
- }
-
- @Override
- public void close() {
- SendableRegistry.remove(this);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SensorUtil.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SensorUtil.java
index 22aa7bd..0ac24de 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SensorUtil.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SensorUtil.java
@@ -1,92 +1,55 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.AnalogJNI;
import edu.wpi.first.hal.ConstantsJNI;
import edu.wpi.first.hal.DIOJNI;
-import edu.wpi.first.hal.PDPJNI;
import edu.wpi.first.hal.PWMJNI;
import edu.wpi.first.hal.PortsJNI;
import edu.wpi.first.hal.RelayJNI;
-import edu.wpi.first.hal.SolenoidJNI;
/**
* Stores most recent status information as well as containing utility functions for checking
* channels and error processing.
*/
public final class SensorUtil {
- /**
- * Ticks per microsecond.
- */
- public static final int kSystemClockTicksPerMicrosecond
- = ConstantsJNI.getSystemClockTicksPerMicrosecond();
+ /** Ticks per microsecond. */
+ public static final int kSystemClockTicksPerMicrosecond =
+ ConstantsJNI.getSystemClockTicksPerMicrosecond();
- /**
- * Number of digital channels per roboRIO.
- */
+ /** Number of digital channels per roboRIO. */
public static final int kDigitalChannels = PortsJNI.getNumDigitalChannels();
- /**
- * Number of analog input channels per roboRIO.
- */
+ /** Number of analog input channels per roboRIO. */
public static final int kAnalogInputChannels = PortsJNI.getNumAnalogInputs();
- /**
- * Number of analog output channels per roboRIO.
- */
+ /** Number of analog output channels per roboRIO. */
public static final int kAnalogOutputChannels = PortsJNI.getNumAnalogOutputs();
- /**
- * Number of solenoid channels per module.
- */
- public static final int kSolenoidChannels = PortsJNI.getNumSolenoidChannels();
+ /** Number of solenoid channels per module. */
+ public static final int kCTRESolenoidChannels = PortsJNI.getNumCTRESolenoidChannels();
- /**
- * Number of PWM channels per roboRIO.
- */
+ /** Number of PWM channels per roboRIO. */
public static final int kPwmChannels = PortsJNI.getNumPWMChannels();
- /**
- * Number of relay channels per roboRIO.
- */
+ /** Number of relay channels per roboRIO. */
public static final int kRelayChannels = PortsJNI.getNumRelayHeaders();
- /**
- * Number of power distribution channels per PDP.
- */
- public static final int kPDPChannels = PortsJNI.getNumPDPChannels();
+ /** Number of power distribution channels per PDP. */
+ public static final int kCTREPDPChannels = PortsJNI.getNumCTREPDPChannels();
- /**
- * Number of power distribution modules per PDP.
- */
- public static final int kPDPModules = PortsJNI.getNumPDPModules();
+ /** Number of power distribution modules per PDP. */
+ public static final int kCTREPDPModules = PortsJNI.getNumCTREPDPModules();
- /**
- * Number of PCM Modules.
- */
- public static final int kPCMModules = PortsJNI.getNumPCMModules();
+ /** Number of PCM Modules. */
+ public static final int kCTREPCMModules = PortsJNI.getNumCTREPCMModules();
- /**
- * Verify that the solenoid module is correct.
- *
- * @param moduleNumber The solenoid module module number to check.
- */
- public static void checkSolenoidModule(final int moduleNumber) {
- if (!SolenoidJNI.checkSolenoidModule(moduleNumber)) {
- StringBuilder buf = new StringBuilder();
- buf.append("Requested solenoid module is out of range. Minimum: 0, Maximum: ")
- .append(kPCMModules)
- .append(", Requested: ")
- .append(moduleNumber);
- throw new IllegalArgumentException(buf.toString());
- }
- }
+ public static final int kREVPHChannels = PortsJNI.getNumREVPHChannels();
+
+ public static final int kREVPHModules = PortsJNI.getNumREVPHModules();
/**
* Check that the digital channel number is valid. Verify that the channel number is one of the
@@ -98,9 +61,9 @@
if (!DIOJNI.checkDIOChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested DIO channel is out of range. Minimum: 0, Maximum: ")
- .append(kDigitalChannels)
- .append(", Requested: ")
- .append(channel);
+ .append(kDigitalChannels)
+ .append(", Requested: ")
+ .append(channel);
throw new IllegalArgumentException(buf.toString());
}
}
@@ -115,9 +78,9 @@
if (!RelayJNI.checkRelayChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested relay channel is out of range. Minimum: 0, Maximum: ")
- .append(kRelayChannels)
- .append(", Requested: ")
- .append(channel);
+ .append(kRelayChannels)
+ .append(", Requested: ")
+ .append(channel);
throw new IllegalArgumentException(buf.toString());
}
}
@@ -132,9 +95,9 @@
if (!PWMJNI.checkPWMChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested PWM channel is out of range. Minimum: 0, Maximum: ")
- .append(kPwmChannels)
- .append(", Requested: ")
- .append(channel);
+ .append(kPwmChannels)
+ .append(", Requested: ")
+ .append(channel);
throw new IllegalArgumentException(buf.toString());
}
}
@@ -149,9 +112,9 @@
if (!AnalogJNI.checkAnalogInputChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested analog input channel is out of range. Minimum: 0, Maximum: ")
- .append(kAnalogInputChannels)
- .append(", Requested: ")
- .append(channel);
+ .append(kAnalogInputChannels)
+ .append(", Requested: ")
+ .append(channel);
throw new IllegalArgumentException(buf.toString());
}
}
@@ -166,58 +129,9 @@
if (!AnalogJNI.checkAnalogOutputChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested analog output channel is out of range. Minimum: 0, Maximum: ")
- .append(kAnalogOutputChannels)
- .append(", Requested: ")
- .append(channel);
- throw new IllegalArgumentException(buf.toString());
- }
- }
-
- /**
- * Verify that the solenoid channel number is within limits. Channel numbers are 0-based.
- *
- * @param channel The channel number to check.
- */
- public static void checkSolenoidChannel(final int channel) {
- if (!SolenoidJNI.checkSolenoidChannel(channel)) {
- StringBuilder buf = new StringBuilder();
- buf.append("Requested solenoid channel is out of range. Minimum: 0, Maximum: ")
- .append(kSolenoidChannels)
- .append(", Requested: ")
- .append(channel);
- throw new IllegalArgumentException(buf.toString());
- }
- }
-
- /**
- * Verify that the power distribution channel number is within limits. Channel numbers are
- * 0-based.
- *
- * @param channel The channel number to check.
- */
- public static void checkPDPChannel(final int channel) {
- if (!PDPJNI.checkPDPChannel(channel)) {
- StringBuilder buf = new StringBuilder();
- buf.append("Requested PDP channel is out of range. Minimum: 0, Maximum: ")
- .append(kPDPChannels)
- .append(", Requested: ")
- .append(channel);
- throw new IllegalArgumentException(buf.toString());
- }
- }
-
- /**
- * Verify that the PDP module number is within limits. module numbers are 0-based.
- *
- * @param module The module number to check.
- */
- public static void checkPDPModule(final int module) {
- if (!PDPJNI.checkPDPModule(module)) {
- StringBuilder buf = new StringBuilder();
- buf.append("Requested PDP module is out of range. Minimum: 0, Maximum: ")
- .append(kPDPModules)
- .append(", Requested: ")
- .append(module);
+ .append(kAnalogOutputChannels)
+ .append(", Requested: ")
+ .append(channel);
throw new IllegalArgumentException(buf.toString());
}
}
@@ -227,10 +141,20 @@
*
* @return The number of the default solenoid module.
*/
- public static int getDefaultSolenoidModule() {
+ @SuppressWarnings("AbbreviationAsWordInName")
+ public static int getDefaultCTREPCMModule() {
return 0;
}
- private SensorUtil() {
+ /**
+ * Get the number of the default solenoid module.
+ *
+ * @return The number of the default solenoid module.
+ */
+ @SuppressWarnings("AbbreviationAsWordInName")
+ public static int getDefaultREVPHModule() {
+ return 1;
}
+
+ private SensorUtil() {}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SerialPort.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SerialPort.java
index 0f509c7..331bbf1 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SerialPort.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SerialPort.java
@@ -1,28 +1,25 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.nio.charset.StandardCharsets;
-
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SerialPortJNI;
+import java.nio.charset.StandardCharsets;
-/**
- * Driver for the serial ports (USB, MXP, Onboard) on the roboRIO.
- */
+/** Driver for the serial ports (USB, MXP, Onboard) on the roboRIO. */
public class SerialPort implements AutoCloseable {
private int m_portHandle;
public enum Port {
- kOnboard(0), kMXP(1), kUSB(2), kUSB1(2), kUSB2(3);
+ kOnboard(0),
+ kMXP(1),
+ kUSB(2),
+ kUSB1(2),
+ kUSB2(3);
- @SuppressWarnings("MemberName")
public final int value;
Port(int value) {
@@ -30,13 +27,14 @@
}
}
- /**
- * Represents the parity to use for serial communications.
- */
+ /** Represents the parity to use for serial communications. */
public enum Parity {
- kNone(0), kOdd(1), kEven(2), kMark(3), kSpace(4);
+ kNone(0),
+ kOdd(1),
+ kEven(2),
+ kMark(3),
+ kSpace(4);
- @SuppressWarnings("MemberName")
public final int value;
Parity(int value) {
@@ -44,13 +42,12 @@
}
}
- /**
- * Represents the number of stop bits to use for Serial Communication.
- */
+ /** Represents the number of stop bits to use for Serial Communication. */
public enum StopBits {
- kOne(10), kOnePointFive(15), kTwo(20);
+ kOne(10),
+ kOnePointFive(15),
+ kTwo(20);
- @SuppressWarnings("MemberName")
public final int value;
StopBits(int value) {
@@ -58,13 +55,13 @@
}
}
- /**
- * Represents what type of flow control to use for serial communication.
- */
+ /** Represents what type of flow control to use for serial communication. */
public enum FlowControl {
- kNone(0), kXonXoff(1), kRtsCts(2), kDtsDsr(4);
+ kNone(0),
+ kXonXoff(1),
+ kRtsCts(2),
+ kDtsDsr(4);
- @SuppressWarnings("MemberName")
public final int value;
FlowControl(int value) {
@@ -72,13 +69,11 @@
}
}
- /**
- * Represents which type of buffer mode to use when writing to a serial port.
- */
+ /** Represents which type of buffer mode to use when writing to a serial port. */
public enum WriteBufferMode {
- kFlushOnAccess(1), kFlushWhenFull(2);
+ kFlushOnAccess(1),
+ kFlushWhenFull(2);
- @SuppressWarnings("MemberName")
public final int value;
WriteBufferMode(int value) {
@@ -89,19 +84,25 @@
/**
* Create an instance of a Serial Port class.
*
- * <p>Prefer to use the constructor that doesn't take a port name, but in some
- * cases the automatic detection might not work correctly.
+ * <p>Prefer to use the constructor that doesn't take a port name, but in some cases the automatic
+ * detection might not work correctly.
*
* @param baudRate The baud rate to configure the serial port.
- * @param port The Serial port to use
+ * @param port The Serial port to use
* @param portName The direct portName to use
* @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
- * @param parity Select the type of parity checking to use.
+ * @param parity Select the type of parity checking to use.
* @param stopBits The number of stop bits to use as defined by the enum StopBits.
- * @deprecated Will be removed for 2019
+ * @deprecated Will be removed for 2019
*/
- public SerialPort(final int baudRate, String portName, Port port, final int dataBits,
- Parity parity, StopBits stopBits) {
+ @Deprecated
+ public SerialPort(
+ final int baudRate,
+ String portName,
+ Port port,
+ final int dataBits,
+ Parity parity,
+ StopBits stopBits) {
m_portHandle = SerialPortJNI.serialInitializePortDirect((byte) port.value, portName);
SerialPortJNI.serialSetBaudRate(m_portHandle, baudRate);
SerialPortJNI.serialSetDataBits(m_portHandle, (byte) dataBits);
@@ -126,13 +127,13 @@
* Create an instance of a Serial Port class.
*
* @param baudRate The baud rate to configure the serial port.
- * @param port The Serial port to use
+ * @param port The Serial port to use
* @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
- * @param parity Select the type of parity checking to use.
+ * @param parity Select the type of parity checking to use.
* @param stopBits The number of stop bits to use as defined by the enum StopBits.
*/
- public SerialPort(final int baudRate, Port port, final int dataBits, Parity parity,
- StopBits stopBits) {
+ public SerialPort(
+ final int baudRate, Port port, final int dataBits, Parity parity, StopBits stopBits) {
m_portHandle = SerialPortJNI.serialInitializePort((byte) port.value);
SerialPortJNI.serialSetBaudRate(m_portHandle, baudRate);
SerialPortJNI.serialSetDataBits(m_portHandle, (byte) dataBits);
@@ -157,8 +158,9 @@
* Create an instance of a Serial Port class. Defaults to one stop bit.
*
* @param baudRate The baud rate to configure the serial port.
+ * @param port The serial port to use.
* @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
- * @param parity Select the type of parity checking to use.
+ * @param parity Select the type of parity checking to use.
*/
public SerialPort(final int baudRate, Port port, final int dataBits, Parity parity) {
this(baudRate, port, dataBits, parity, StopBits.kOne);
@@ -168,6 +170,7 @@
* Create an instance of a Serial Port class. Defaults to no parity and one stop bit.
*
* @param baudRate The baud rate to configure the serial port.
+ * @param port The serial port to use.
* @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
*/
public SerialPort(final int baudRate, Port port, final int dataBits) {
@@ -175,10 +178,10 @@
}
/**
- * Create an instance of a Serial Port class. Defaults to 8 databits, no parity, and one stop
- * bit.
+ * Create an instance of a Serial Port class. Defaults to 8 databits, no parity, and one stop bit.
*
* @param baudRate The baud rate to configure the serial port.
+ * @param port The serial port to use.
*/
public SerialPort(final int baudRate, Port port) {
this(baudRate, port, 8, Parity.kNone, StopBits.kOne);
@@ -226,9 +229,7 @@
enableTermination('\n');
}
- /**
- * Disable termination behavior.
- */
+ /** Disable termination behavior. */
public void disableTermination() {
SerialPortJNI.serialDisableTermination(m_portHandle);
}
@@ -283,7 +284,7 @@
* Write raw bytes to the serial port.
*
* @param buffer The buffer of bytes to write.
- * @param count The maximum number of bytes to write.
+ * @param count The maximum number of bytes to write.
* @return The number of bytes actually written into the port.
*/
public int write(byte[] buffer, int count) {
@@ -344,11 +345,11 @@
/**
* Specify the flushing behavior of the output buffer.
*
- * <p>When set to kFlushOnAccess, data is synchronously written to the serial port after each
- * call to either print() or write().
+ * <p>When set to kFlushOnAccess, data is synchronously written to the serial port after each call
+ * to either print() or write().
*
- * <p>When set to kFlushWhenFull, data will only be written to the serial port when the buffer
- * is full or when flush() is called.
+ * <p>When set to kFlushWhenFull, data will only be written to the serial port when the buffer is
+ * full or when flush() is called.
*
* @param mode The write buffer mode.
*/
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Servo.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Servo.java
index 6b2eab6..f11f8f9 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Servo.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Servo.java
@@ -1,16 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
* Standard hobby style servo.
@@ -28,11 +25,11 @@
/**
* Constructor.<br>
*
- * <p>By default {@value #kDefaultMaxServoPWM} ms is used as the maxPWM value<br> By default
- * {@value #kDefaultMinServoPWM} ms is used as the minPWM value<br>
+ * <p>By default {@value #kDefaultMaxServoPWM} ms is used as the maxPWM value<br>
+ * By default {@value #kDefaultMinServoPWM} ms is used as the minPWM value<br>
*
* @param channel The PWM channel to which the servo is attached. 0-9 are on-board, 10-19 are on
- * the MXP port
+ * the MXP port
*/
public Servo(final int channel) {
super(channel);
@@ -43,7 +40,6 @@
SendableRegistry.setName(this, "Servo", getChannel());
}
-
/**
* Set the servo position.
*
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SlewRateLimiter.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SlewRateLimiter.java
deleted file mode 100644
index fe4dda7..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SlewRateLimiter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.wpiutil.math.MathUtil;
-
-/**
- * A class that limits the rate of change of an input value. Useful for implementing voltage,
- * setpoint, and/or output ramps. A slew-rate limit is most appropriate when the quantity being
- * controlled is a velocity or a voltage; when controlling a position, consider using a
- * {@link edu.wpi.first.wpilibj.trajectory.TrapezoidProfile} instead.
- */
-public class SlewRateLimiter {
- private final double m_rateLimit;
- private double m_prevVal;
- private double m_prevTime;
-
- /**
- * Creates a new SlewRateLimiter with the given rate limit and initial value.
- *
- * @param rateLimit The rate-of-change limit, in units per second.
- * @param initialValue The initial value of the input.
- */
- public SlewRateLimiter(double rateLimit, double initialValue) {
- m_rateLimit = rateLimit;
- m_prevVal = initialValue;
- m_prevTime = Timer.getFPGATimestamp();
- }
-
- /**
- * Creates a new SlewRateLimiter with the given rate limit and an initial value of zero.
- *
- * @param rateLimit The rate-of-change limit, in units per second.
- */
- public SlewRateLimiter(double rateLimit) {
- this(rateLimit, 0);
- }
-
- /**
- * Filters the input to limit its slew rate.
- *
- * @param input The input value whose slew rate is to be limited.
- * @return The filtered value, which will not change faster than the slew rate.
- */
- public double calculate(double input) {
- double currentTime = Timer.getFPGATimestamp();
- double elapsedTime = currentTime - m_prevTime;
- m_prevVal += MathUtil.clamp(input - m_prevVal,
- -m_rateLimit * elapsedTime,
- m_rateLimit * elapsedTime);
- m_prevTime = currentTime;
- return m_prevVal;
- }
-
- /**
- * Resets the slew rate limiter to the specified value; ignores the rate limit when doing so.
- *
- * @param value The value to reset to.
- */
- public void reset(double value) {
- m_prevVal = value;
- m_prevTime = Timer.getFPGATimestamp();
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Solenoid.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Solenoid.java
index 6245c2b..e86042b 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Solenoid.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Solenoid.java
@@ -1,62 +1,83 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.hal.SolenoidJNI;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.hal.util.AllocationException;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
/**
- * Solenoid class for running high voltage Digital Output on the PCM.
+ * Solenoid class for running high voltage Digital Output on a pneumatics module.
*
- * <p>The Solenoid class is typically used for pneumatic solenoids, but could be used for any
- * device within the current spec of the PCM.
+ * <p>The Solenoid class is typically used for pneumatic solenoids, but could be used for any device
+ * within the current spec of the module.
*/
-public class Solenoid extends SolenoidBase implements Sendable, AutoCloseable {
- private final int m_channel; // The channel to control.
- private int m_solenoidHandle;
+public class Solenoid implements Sendable, AutoCloseable {
+ private final int m_mask; // The channel mask
+ private final int m_channel;
+ private PneumaticsBase m_module;
/**
- * Constructor using the default PCM ID (defaults to 0).
+ * Constructs a solenoid for a default module and specified type.
*
- * @param channel The channel on the PCM to control (0..7).
+ * @param moduleType The module type to use.
+ * @param channel The channel the solenoid is on.
*/
- public Solenoid(final int channel) {
- this(SensorUtil.getDefaultSolenoidModule(), channel);
+ public Solenoid(final PneumaticsModuleType moduleType, final int channel) {
+ this(PneumaticsBase.getDefaultForType(moduleType), moduleType, channel);
}
/**
- * Constructor.
+ * Constructs a solenoid for a specified module and type.
*
- * @param moduleNumber The CAN ID of the PCM the solenoid is attached to.
- * @param channel The channel on the PCM to control (0..7).
+ * @param module The module ID to use.
+ * @param moduleType The module type to use.
+ * @param channel The channel the solenoid is on.
*/
- public Solenoid(final int moduleNumber, final int channel) {
- super(moduleNumber);
+ public Solenoid(final int module, final PneumaticsModuleType moduleType, final int channel) {
+ m_module = PneumaticsBase.getForType(module, moduleType);
+ boolean allocatedSolenoids = false;
+ boolean successfulCompletion = false;
+
+ m_mask = 1 << channel;
m_channel = channel;
- SensorUtil.checkSolenoidModule(m_moduleNumber);
- SensorUtil.checkSolenoidChannel(m_channel);
+ try {
+ if (!m_module.checkSolenoidChannel(channel)) {
+ throw new IllegalArgumentException("Channel " + channel + " out of range");
+ }
- int portHandle = HAL.getPortWithModule((byte) m_moduleNumber, (byte) m_channel);
- m_solenoidHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
+ if (m_module.checkAndReserveSolenoids(m_mask) != 0) {
+ throw new AllocationException("Solenoid already allocated");
+ }
- HAL.report(tResourceType.kResourceType_Solenoid, m_channel + 1, m_moduleNumber + 1);
- SendableRegistry.addLW(this, "Solenoid", m_moduleNumber, m_channel);
+ allocatedSolenoids = true;
+
+ HAL.report(tResourceType.kResourceType_Solenoid, channel + 1, m_module.getModuleNumber() + 1);
+ SendableRegistry.addLW(this, "Solenoid", m_module.getModuleNumber(), channel);
+ successfulCompletion = true;
+
+ } finally {
+ if (!successfulCompletion) {
+ if (allocatedSolenoids) {
+ m_module.unreserveSolenoids(m_mask);
+ }
+ m_module.close();
+ }
+ }
}
@Override
public void close() {
SendableRegistry.remove(this);
- SolenoidJNI.freeSolenoidPort(m_solenoidHandle);
- m_solenoidHandle = 0;
+ m_module.unreserveSolenoids(m_mask);
+ m_module.close();
+ m_module = null;
}
/**
@@ -65,7 +86,8 @@
* @param on True will turn the solenoid output on. False will turn the solenoid output off.
*/
public void set(boolean on) {
- SolenoidJNI.setSolenoid(m_solenoidHandle, on);
+ int value = on ? (0xFFFF & m_mask) : 0;
+ m_module.setSolenoids(m_mask, value);
}
/**
@@ -74,7 +96,8 @@
* @return True if the solenoid output is on or false if the solenoid output is off.
*/
public boolean get() {
- return SolenoidJNI.getSolenoid(m_solenoidHandle);
+ int currentAll = m_module.getSolenoids();
+ return (currentAll & m_mask) != 0;
}
/**
@@ -88,39 +111,44 @@
}
/**
- * Check if solenoid is blacklisted. If a solenoid is shorted, it is added to the blacklist and
- * disabled until power cycle, or until faults are cleared.
+ * Get the channel this solenoid is connected to.
*
- * @return If solenoid is disabled due to short.
- * @see #clearAllPCMStickyFaults()
+ * @return The channel this solenoid is connected to.
*/
- public boolean isBlackListed() {
- int value = getPCMSolenoidBlackList() & (1 << m_channel);
- return value != 0;
+ public int getChannel() {
+ return m_channel;
}
/**
- * Set the pulse duration in the PCM. This is used in conjunction with
- * the startPulse method to allow the PCM to control the timing of a pulse.
- * The timing can be controlled in 0.01 second increments.
+ * Check if solenoid is DisabledListed. If a solenoid is shorted, it is added to the Disabled List
+ * and disabled until power cycle, or until faults are cleared.
+ *
+ * @return If solenoid is disabled due to short.
+ */
+ public boolean isDisabled() {
+ return (m_module.getSolenoidDisabledList() & m_mask) != 0;
+ }
+
+ /**
+ * Set the pulse duration in the PCM. This is used in conjunction with the startPulse method to
+ * allow the PCM to control the timing of a pulse. The timing can be controlled in 0.01 second
+ * increments.
*
* @param durationSeconds The duration of the pulse, from 0.01 to 2.55 seconds.
- *
* @see #startPulse()
*/
public void setPulseDuration(double durationSeconds) {
long durationMS = (long) (durationSeconds * 1000);
- SolenoidJNI.setOneShotDuration(m_solenoidHandle, durationMS);
+ m_module.setOneShotDuration(m_channel, (int) durationMS);
}
/**
- * Trigger the PCM to generate a pulse of the duration set in
- * setPulseDuration.
+ * Trigger the PCM to generate a pulse of the duration set in setPulseDuration.
*
* @see #setPulseDuration(double)
*/
public void startPulse() {
- SolenoidJNI.fireOneShot(m_solenoidHandle);
+ m_module.fireOneShot(m_channel);
}
@Override
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SolenoidBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SolenoidBase.java
deleted file mode 100644
index a778d8c..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SolenoidBase.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.SolenoidJNI;
-
-/**
- * SolenoidBase class is the common base class for the {@link Solenoid} and {@link DoubleSolenoid}
- * classes.
- */
-public class SolenoidBase {
- protected final int m_moduleNumber; // The number of the solenoid module being used.
-
- /**
- * Constructor.
- *
- * @param moduleNumber The PCM CAN ID
- */
- protected SolenoidBase(final int moduleNumber) {
- m_moduleNumber = moduleNumber;
- }
-
- /**
- * Read all 8 solenoids from the specified module as a single byte.
- *
- * @param moduleNumber the module number to read
- * @return The current value of all 8 solenoids on the module.
- */
- public static int getAll(int moduleNumber) {
- return SolenoidJNI.getAllSolenoids(moduleNumber);
- }
-
- /**
- * Read all 8 solenoids from the module used by this solenoid as a single byte.
- *
- * @return The current value of all 8 solenoids on this module.
- */
- public int getAll() {
- return SolenoidBase.getAll(m_moduleNumber);
- }
-
- /**
- * Reads complete solenoid blacklist for all 8 solenoids as a single byte. If a solenoid is
- * shorted, it is added to the blacklist and disabled until power cycle, or until faults are
- * cleared.
- *
- * @param moduleNumber the module number to read
- * @return The solenoid blacklist of all 8 solenoids on the module.
- * @see #clearAllPCMStickyFaults()
- */
- public static int getPCMSolenoidBlackList(int moduleNumber) {
- return SolenoidJNI.getPCMSolenoidBlackList(moduleNumber);
- }
-
- /**
- * Reads complete solenoid blacklist for all 8 solenoids as a single byte. If a solenoid is
- * shorted, it is added to the blacklist and disabled until power cycle, or until faults are
- * cleared.
- *
- * @return The solenoid blacklist of all 8 solenoids on the module.
- * @see #clearAllPCMStickyFaults()
- */
- public int getPCMSolenoidBlackList() {
- return SolenoidBase.getPCMSolenoidBlackList(m_moduleNumber);
- }
-
- /**
- * If true, the common highside solenoid voltage rail is too low, most likely a solenoid channel
- * is shorted.
- *
- * @param moduleNumber the module number to read
- * @return true if PCM sticky fault is set
- */
- public static boolean getPCMSolenoidVoltageStickyFault(int moduleNumber) {
- return SolenoidJNI.getPCMSolenoidVoltageStickyFault(moduleNumber);
- }
-
- /**
- * If true, the common highside solenoid voltage rail is too low, most likely a solenoid channel
- * is shorted.
- *
- * @return true if PCM sticky fault is set
- */
- public boolean getPCMSolenoidVoltageStickyFault() {
- return SolenoidBase.getPCMSolenoidVoltageStickyFault(m_moduleNumber);
- }
-
- /**
- * The common highside solenoid voltage rail is too low, most likely a solenoid channel is
- * shorted.
- *
- * @param moduleNumber the module number to read
- * @return true if PCM is in fault state.
- */
- public static boolean getPCMSolenoidVoltageFault(int moduleNumber) {
- return SolenoidJNI.getPCMSolenoidVoltageFault(moduleNumber);
- }
-
- /**
- * The common highside solenoid voltage rail is too low, most likely a solenoid channel is
- * shorted.
- *
- * @return true if PCM is in fault state.
- */
- public boolean getPCMSolenoidVoltageFault() {
- return SolenoidBase.getPCMSolenoidVoltageFault(m_moduleNumber);
- }
-
- /**
- * Clear ALL sticky faults inside PCM that Compressor is wired to.
- *
- * <p>If a sticky fault is set, then it will be persistently cleared. Compressor drive maybe
- * momentarily disable while flags are being cleared. Care should be taken to not call this too
- * frequently, otherwise normal compressor functionality may be prevented.
- *
- * <p>If no sticky faults are set then this call will have no effect.
- *
- * @param moduleNumber the module number to read
- */
- public static void clearAllPCMStickyFaults(int moduleNumber) {
- SolenoidJNI.clearAllPCMStickyFaults(moduleNumber);
- }
-
- /**
- * Clear ALL sticky faults inside PCM that Compressor is wired to.
- *
- * <p>If a sticky fault is set, then it will be persistently cleared. Compressor drive maybe
- * momentarily disable while flags are being cleared. Care should be taken to not call this too
- * frequently, otherwise normal compressor functionality may be prevented.
- *
- * <p>If no sticky faults are set then this call will have no effect.
- */
- public void clearAllPCMStickyFaults() {
- SolenoidBase.clearAllPCMStickyFaults(m_moduleNumber);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Spark.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Spark.java
deleted file mode 100644
index c8bacbf..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Spark.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * REV Robotics SPARK Speed Controller.
- *
- * <p>Note that the SPARK uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the Spark User Manual
- * available from REV Robotics.
- *
- * <p><ul>
- * <li>2.003ms = full "forward"
- * <li>1.550ms = the "high end" of the deadband range
- * <li>1.500ms = center of the deadband range (off)
- * <li>1.460ms = the "low end" of the deadband range
- * <li>0.999ms = full "reverse"
- * </ul>
- */
-public class Spark extends PWMSpeedController {
- /**
- * Common initialization code called by all constructors.
- */
- protected void initSpark() {
- setBounds(2.003, 1.55, 1.50, 1.46, 0.999);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_RevSPARK, getChannel() + 1);
- SendableRegistry.setName(this, "Spark", getChannel());
- }
-
- /**
- * Constructor.
- *
- * @param channel The PWM channel that the SPARK is attached to. 0-9 are on-board, 10-19 are on
- * the MXP port
- */
- public Spark(final int channel) {
- super(channel);
- initSpark();
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedController.java
index 4407ff0..490455c 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedController.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedController.java
@@ -1,28 +1,28 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
/**
- * Interface for speed controlling devices.
+ * Interface for motor controlling devices.
+ *
+ * @deprecated Use {@link edu.wpi.first.wpilibj.motorcontrol.MotorController}.
*/
-public interface SpeedController extends PIDOutput {
+@Deprecated(since = "2022", forRemoval = true)
+public interface SpeedController {
/**
- * Common interface for setting the speed of a speed controller.
+ * Common interface for setting the speed of a motor controller.
*
* @param speed The speed to set. Value should be between -1.0 and 1.0.
*/
void set(double speed);
/**
- * Sets the voltage output of the SpeedController. Compensates for the current bus
- * voltage to ensure that the desired voltage is output even if the battery voltage is below
- * 12V - highly useful when the voltage outputs are "meaningful" (e.g. they come from a
- * feedforward calculation).
+ * Sets the voltage output of the MotorController. Compensates for the current bus voltage to
+ * ensure that the desired voltage is output even if the battery voltage is below 12V - highly
+ * useful when the voltage outputs are "meaningful" (e.g. they come from a feedforward
+ * calculation).
*
* <p>NOTE: This function *must* be called regularly in order for voltage compensation to work
* properly - unlike the ordinary set function, it is not "set it and forget it."
@@ -34,29 +34,27 @@
}
/**
- * Common interface for getting the current set speed of a speed controller.
+ * Common interface for getting the current set speed of a motor controller.
*
* @return The current set speed. Value is between -1.0 and 1.0.
*/
double get();
/**
- * Common interface for inverting direction of a speed controller.
+ * Common interface for inverting direction of a motor controller.
*
* @param isInverted The state of inversion true is inverted.
*/
void setInverted(boolean isInverted);
/**
- * Common interface for returning if a speed controller is in the inverted state or not.
+ * Common interface for returning if a motor controller is in the inverted state or not.
*
* @return isInverted The state of the inversion true is inverted.
*/
boolean getInverted();
- /**
- * Disable the speed controller.
- */
+ /** Disable the motor controller. */
void disable();
/**
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedControllerGroup.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedControllerGroup.java
index 81b5470..d2217b7 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedControllerGroup.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SpeedControllerGroup.java
@@ -1,21 +1,23 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+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.motorcontrol.MotorController;
import java.util.Arrays;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
/**
* Allows multiple {@link SpeedController} objects to be linked together.
+ *
+ * @deprecated Use {@link edu.wpi.first.wpilibj.motorcontrol.MotorControllerGroup}.
*/
-public class SpeedControllerGroup implements SpeedController, Sendable, AutoCloseable {
+@Deprecated(since = "2022", forRemoval = true)
+@SuppressWarnings("removal")
+public class SpeedControllerGroup implements MotorController, Sendable, AutoCloseable {
private boolean m_isInverted;
private final SpeedController[] m_speedControllers;
private static int instances;
@@ -23,16 +25,14 @@
/**
* Create a new SpeedControllerGroup with the provided SpeedControllers.
*
+ * @param speedController The first SpeedController to add.
* @param speedControllers The SpeedControllers to add
*/
- @SuppressWarnings("PMD.AvoidArrayLoops")
- public SpeedControllerGroup(SpeedController speedController,
- SpeedController... speedControllers) {
+ public SpeedControllerGroup(
+ SpeedController speedController, SpeedController... speedControllers) {
m_speedControllers = new SpeedController[speedControllers.length + 1];
m_speedControllers[0] = speedController;
- for (int i = 0; i < speedControllers.length; i++) {
- m_speedControllers[i + 1] = speedControllers[i];
- }
+ System.arraycopy(speedControllers, 0, m_speedControllers, 1, speedControllers.length);
init();
}
@@ -46,7 +46,7 @@
SendableRegistry.addChild(this, controller);
}
instances++;
- SendableRegistry.addLW(this, "SpeedControllerGroup", instances);
+ SendableRegistry.addLW(this, "MotorControllerGroup", instances);
}
@Override
@@ -94,13 +94,8 @@
}
@Override
- public void pidWrite(double output) {
- set(output);
- }
-
- @Override
public void initSendable(SendableBuilder builder) {
- builder.setSmartDashboardType("Speed Controller");
+ builder.setSmartDashboardType("Motor Controller");
builder.setActuator(true);
builder.setSafeState(this::stopMotor);
builder.addDoubleProperty("Value", this::get, this::set);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SynchronousInterrupt.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SynchronousInterrupt.java
new file mode 100644
index 0000000..1e7a54d
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SynchronousInterrupt.java
@@ -0,0 +1,165 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+
+import edu.wpi.first.hal.InterruptJNI;
+
+/**
+ * Class for handling synchronous (blocking) interrupts.
+ *
+ * <p>By default, interrupts will occur on rising edge.
+ *
+ * <p>Asynchronous interrupts are handled by the AsynchronousInterrupt class.
+ */
+public class SynchronousInterrupt implements AutoCloseable {
+ @SuppressWarnings("PMD.SingularField")
+ private final DigitalSource m_source;
+
+ private final int m_handle;
+
+ @SuppressWarnings("JavadocMethod")
+ public enum WaitResult {
+ kTimeout(0x0),
+ kRisingEdge(0x1),
+ kFallingEdge(0x100),
+ kBoth(0x101);
+
+ @SuppressWarnings("MemberName")
+ public final int value;
+
+ WaitResult(int value) {
+ this.value = value;
+ }
+
+ /**
+ * Create a wait result enum.
+ *
+ * @param rising True if a rising edge occurred.
+ * @param falling True if a falling edge occurred.
+ * @return A wait result enum.
+ */
+ public static WaitResult getValue(boolean rising, boolean falling) {
+ if (rising && falling) {
+ return kBoth;
+ } else if (rising) {
+ return kRisingEdge;
+ } else if (falling) {
+ return kFallingEdge;
+ } else {
+ return kTimeout;
+ }
+ }
+ }
+
+ /**
+ * Constructs a new synchronous interrupt using a DigitalSource.
+ *
+ * <p>At construction, the interrupt will trigger on the rising edge.
+ *
+ * @param source The digital source to use.
+ */
+ public SynchronousInterrupt(DigitalSource source) {
+ m_source = requireNonNullParam(source, "source", "SynchronousInterrupt");
+ m_handle = InterruptJNI.initializeInterrupts();
+ InterruptJNI.requestInterrupts(
+ m_handle, m_source.getPortHandleForRouting(), m_source.getAnalogTriggerTypeForRouting());
+ InterruptJNI.setInterruptUpSourceEdge(m_handle, true, false);
+ }
+
+ /**
+ * Closes the interrupt.
+ *
+ * <p>This does not close the associated digital source.
+ */
+ @Override
+ public void close() {
+ InterruptJNI.cleanInterrupts(m_handle);
+ }
+
+ /**
+ * Wait for interrupt that returns the raw result value from the hardware.
+ *
+ * <p>Used by AsynchronousInterrupt. Users should use waitForInterrupt.
+ *
+ * @param timeoutSeconds The timeout in seconds. 0 or less will return immediately.
+ * @param ignorePrevious True to ignore if a previous interrupt has occurred, and only wait for a
+ * new trigger. False will consider if an interrupt has occurred since the last time the
+ * interrupt was read.
+ * @return The raw hardware interrupt result
+ */
+ int waitForInterruptRaw(double timeoutSeconds, boolean ignorePrevious) {
+ return InterruptJNI.waitForInterrupt(m_handle, timeoutSeconds, ignorePrevious);
+ }
+
+ /**
+ * Wait for an interrupt.
+ *
+ * @param timeoutSeconds The timeout in seconds. 0 or less will return immediately.
+ * @param ignorePrevious True to ignore if a previous interrupt has occurred, and only wait for a
+ * new trigger. False will consider if an interrupt has occurred since the last time the
+ * interrupt was read.
+ * @return Result of which edges were triggered, or if an timeout occurred.
+ */
+ public WaitResult waitForInterrupt(double timeoutSeconds, boolean ignorePrevious) {
+ int result = InterruptJNI.waitForInterrupt(m_handle, timeoutSeconds, ignorePrevious);
+
+ // Rising edge result is the interrupt bit set in the byte 0xFF
+ // Falling edge result is the interrupt bit set in the byte 0xFF00
+ // Set any bit set to be true for that edge, and AND the 2 results
+ // together to match the existing enum for all interrupts
+ boolean rising = (result & 0xFF) != 0;
+ boolean falling = (result & 0xFF00) != 0;
+ return WaitResult.getValue(rising, falling);
+ }
+
+ /**
+ * Wait for an interrupt, ignoring any previously occurring interrupts.
+ *
+ * @param timeoutSeconds The timeout in seconds. 0 or less will return immediately.
+ * @return Result of which edges were triggered, or if an timeout occurred.
+ */
+ public WaitResult waitForInterrupt(double timeoutSeconds) {
+ return waitForInterrupt(timeoutSeconds, true);
+ }
+
+ /**
+ * Set which edges to trigger the interrupt on.
+ *
+ * @param risingEdge Trigger on rising edge
+ * @param fallingEdge Trigger on falling edge
+ */
+ public void setInterruptEdges(boolean risingEdge, boolean fallingEdge) {
+ InterruptJNI.setInterruptUpSourceEdge(m_handle, risingEdge, fallingEdge);
+ }
+
+ /**
+ * Get the timestamp of the last rising edge.
+ *
+ * <p>This only works if rising edge was configured using setInterruptEdges.
+ *
+ * @return the timestamp in seconds relative to getFPGATime
+ */
+ public double getRisingTimestamp() {
+ return InterruptJNI.readInterruptRisingTimestamp(m_handle) * 1e-6;
+ }
+
+ /**
+ * Get the timestamp of the last falling edge.
+ *
+ * <p>This only works if falling edge was configured using setInterruptEdges.
+ *
+ * @return the timestamp in seconds relative to getFPGATime
+ */
+ public double getFallingTimestamp() {
+ return InterruptJNI.readInterruptFallingTimestamp(m_handle) * 1e-6;
+ }
+
+ /** Force triggering of any waiting interrupt, which will be seen as a timeout. */
+ public void wakeupWaitingInterrupt() {
+ InterruptJNI.releaseWaitingInterrupt(m_handle);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Talon.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Talon.java
deleted file mode 100644
index 6f20869..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Talon.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * Cross the Road Electronics (CTRE) Talon and Talon SR Speed Controller.
- *
- * <p>Note that the Talon uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the Talon User Manual
- * available from CTRE.
- *
- * <p><ul>
- * <li>2.037ms = full "forward"
- * <li>1.539ms = the "high end" of the deadband range
- * <li>1.513ms = center of the deadband range (off)
- * <li>1.487ms = the "low end" of the deadband range
- * <li>0.989ms = full "reverse"
- * </ul>
- */
-public class Talon extends PWMSpeedController {
- /**
- * Constructor for a Talon (original or Talon SR).
- *
- * @param channel The PWM channel that the Talon is attached to. 0-9 are on-board, 10-19 are on
- * the MXP port
- */
- public Talon(final int channel) {
- super(channel);
-
- setBounds(2.037, 1.539, 1.513, 1.487, 0.989);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_Talon, getChannel() + 1);
- SendableRegistry.setName(this, "Talon", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Threads.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Threads.java
index 7b49d4d..8b0d167 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Threads.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Threads.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -11,35 +8,35 @@
public final class Threads {
/**
- * Get the thread priority for the current thread.
- * @return The current thread priority. Scaled 1-99.
- */
+ * Get the thread priority for the current thread.
+ *
+ * @return The current thread priority. For real-time, this is 1-99 with 99 being highest. For
+ * non-real-time, this is 0. See "man 7 sched" for details.
+ */
public static int getCurrentThreadPriority() {
return ThreadsJNI.getCurrentThreadPriority();
}
/**
- * Get if the current thread is realtime.
- * @return If the current thread is realtime
- */
+ * Get if the current thread is real-time.
+ *
+ * @return If the current thread is real-time.
+ */
public static boolean getCurrentThreadIsRealTime() {
return ThreadsJNI.getCurrentThreadIsRealTime();
}
/**
- * Sets the thread priority for the current thread.
- *
- * @param realTime Set to true to set a realtime priority, false for standard
- * priority
- * @param priority Priority to set the thread to. Scaled 1-99, with 1 being
- * highest. On RoboRIO, priority is ignored for non realtime setting
- *
- * @return The success state of setting the priority
- */
+ * Sets the thread priority for the current thread.
+ *
+ * @param realTime Set to true to set a real-time priority, false for standard priority.
+ * @param priority Priority to set the thread to. For real-time, this is 1-99 with 99 being
+ * highest. For non-real-time, this is forced to 0. See "man 7 sched" for details.
+ * @return True on success.
+ */
public static boolean setCurrentThreadPriority(boolean realTime, int priority) {
return ThreadsJNI.setCurrentThreadPriority(realTime, priority);
}
- private Threads() {
- }
+ private Threads() {}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimedRobot.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimedRobot.java
index 99bce3d..dda62d2 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimedRobot.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimedRobot.java
@@ -1,18 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.PriorityQueue;
-
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.NotifierJNI;
+import java.util.PriorityQueue;
/**
* TimedRobot implements the IterativeRobotBase robot program framework.
@@ -23,7 +19,7 @@
*/
public class TimedRobot extends IterativeRobotBase {
@SuppressWarnings("MemberName")
- class Callback implements Comparable<Callback> {
+ static class Callback implements Comparable<Callback> {
public Runnable func;
public double period;
public double expirationTime;
@@ -31,20 +27,33 @@
/**
* Construct a callback container.
*
- * @param func The callback to run.
- * @param startTimeSeconds The common starting point for all callback
- * scheduling in seconds.
- * @param periodSeconds The period at which to run the callback in
- * seconds.
- * @param offsetSeconds The offset from the common starting time in
- * seconds.
+ * @param func The callback to run.
+ * @param startTimeSeconds The common starting point for all callback scheduling in seconds.
+ * @param periodSeconds The period at which to run the callback in seconds.
+ * @param offsetSeconds The offset from the common starting time in seconds.
*/
Callback(Runnable func, double startTimeSeconds, double periodSeconds, double offsetSeconds) {
this.func = func;
this.period = periodSeconds;
- this.expirationTime = startTimeSeconds + offsetSeconds
- + Math.floor((Timer.getFPGATimestamp() - startTimeSeconds)
- / this.period) * this.period + this.period;
+ this.expirationTime =
+ startTimeSeconds
+ + offsetSeconds
+ + Math.floor((Timer.getFPGATimestamp() - startTimeSeconds) / this.period)
+ * this.period
+ + this.period;
+ }
+
+ @Override
+ public boolean equals(Object rhs) {
+ if (rhs instanceof Callback) {
+ return Double.compare(expirationTime, ((Callback) rhs).expirationTime) == 0;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Double.hashCode(expirationTime);
}
@Override
@@ -65,9 +74,7 @@
private final PriorityQueue<Callback> m_callbacks = new PriorityQueue<>();
- /**
- * Constructor for TimedRobot.
- */
+ /** Constructor for TimedRobot. */
protected TimedRobot() {
this(kDefaultPeriod);
}
@@ -93,9 +100,7 @@
NotifierJNI.cleanNotifier(m_notifier);
}
- /**
- * Provide an alternate "main loop" via startCompetition().
- */
+ /** Provide an alternate "main loop" via startCompetition(). */
@Override
@SuppressWarnings("UnsafeFinalization")
public void startCompetition() {
@@ -106,6 +111,7 @@
}
// Tell the DS that the robot is ready to be enabled
+ System.out.println("********** Robot program startup complete **********");
HAL.observeUserProgramStarting();
// Loop forever, calling the appropriate mode-dependent function
@@ -139,28 +145,19 @@
}
}
- /**
- * Ends the main loop in startCompetition().
- */
+ /** Ends the main loop in startCompetition(). */
@Override
public void endCompetition() {
NotifierJNI.stopNotifier(m_notifier);
}
/**
- * Get time period between calls to Periodic() functions.
- */
- public double getPeriod() {
- return m_period;
- }
-
- /**
* Add a callback to run at a specific period.
*
* <p>This is scheduled on TimedRobot's Notifier, so TimedRobot and the callback run
* synchronously. Interactions between them are thread-safe.
*
- * @param callback The callback to run.
+ * @param callback The callback to run.
* @param periodSeconds The period at which to run the callback in seconds.
*/
public void addPeriodic(Runnable callback, double periodSeconds) {
@@ -173,11 +170,10 @@
* <p>This is scheduled on TimedRobot's Notifier, so TimedRobot and the callback run
* synchronously. Interactions between them are thread-safe.
*
- * @param callback The callback to run.
+ * @param callback The callback to run.
* @param periodSeconds The period at which to run the callback in seconds.
- * @param offsetSeconds The offset from the common starting time in seconds.
- * This is useful for scheduling a callback in a
- * different timeslot relative to TimedRobot.
+ * @param offsetSeconds The offset from the common starting time in seconds. This is useful for
+ * scheduling a callback in a different timeslot relative to TimedRobot.
*/
public void addPeriodic(Runnable callback, double periodSeconds, double offsetSeconds) {
m_callbacks.add(new Callback(callback, m_startTime, periodSeconds, offsetSeconds));
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Timer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Timer.java
index 5d71e72..939e255 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Timer.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Timer.java
@@ -1,12 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+/**
+ * A timer class.
+ *
+ * <p>Note that if the user calls SimHooks.restartTiming(), they should also reset the timer so
+ * get() won't return a negative duration.
+ */
public class Timer {
/**
* Return the system clock time in seconds. Return the time from the FPGA hardware clock in
@@ -23,13 +26,13 @@
* Return the approximate match time. The FMS does not send an official match time to the robots,
* but does send an approximate match time. The value will count down the time remaining in the
* current period (auto or teleop). Warning: This is not an official time (so it cannot be used to
- * dispute ref calls or guarantee that a function will trigger before the match ends) The
- * Practice Match function of the DS approximates the behavior seen on the field.
+ * dispute ref calls or guarantee that a function will trigger before the match ends) The Practice
+ * Match function of the DS approximates the behavior seen on the field.
*
* @return Time remaining in current match period (auto or teleop) in seconds
*/
public static double getMatchTime() {
- return DriverStation.getInstance().getMatchTime();
+ return DriverStation.getMatchTime();
}
/**
@@ -52,12 +55,7 @@
private double m_accumulatedTime;
private boolean m_running;
- /**
- * Lock for synchronization.
- */
- private final Object m_lock = new Object();
-
- @SuppressWarnings("JavadocMethod")
+ @SuppressWarnings("MissingJavadocMethod")
public Timer() {
reset();
}
@@ -74,24 +72,21 @@
* @return Current time value for this timer in seconds
*/
public double get() {
- synchronized (m_lock) {
- if (m_running) {
- return m_accumulatedTime + (getMsClock() - m_startTime) / 1000.0;
- } else {
- return m_accumulatedTime;
- }
+ if (m_running) {
+ return m_accumulatedTime + (getMsClock() - m_startTime) / 1000.0;
+ } else {
+ return m_accumulatedTime;
}
}
/**
- * Reset the timer by setting the time to 0. Make the timer startTime the current time so new
- * requests will be relative now
+ * Reset the timer by setting the time to 0.
+ *
+ * <p>Make the timer startTime the current time so new requests will be relative now.
*/
public void reset() {
- synchronized (m_lock) {
- m_accumulatedTime = 0;
- m_startTime = getMsClock();
- }
+ m_accumulatedTime = 0;
+ m_startTime = getMsClock();
}
/**
@@ -100,11 +95,9 @@
* already running.
*/
public void start() {
- synchronized (m_lock) {
- if (!m_running) {
- m_startTime = getMsClock();
- m_running = true;
- }
+ if (!m_running) {
+ m_startTime = getMsClock();
+ m_running = true;
}
}
@@ -114,10 +107,8 @@
* clock.
*/
public void stop() {
- synchronized (m_lock) {
- m_accumulatedTime = get();
- m_running = false;
- }
+ m_accumulatedTime = get();
+ m_running = false;
}
/**
@@ -127,9 +118,7 @@
* @return Whether the period has passed.
*/
public boolean hasElapsed(double seconds) {
- synchronized (m_lock) {
- return get() > seconds;
- }
+ return get() >= seconds;
}
/**
@@ -139,7 +128,9 @@
*
* @param period The period to check for (in seconds).
* @return Whether the period has passed.
+ * @deprecated Use advanceIfElapsed() instead.
*/
+ @Deprecated(since = "2022", forRemoval = true)
public boolean hasPeriodPassed(double period) {
return advanceIfElapsed(period);
}
@@ -153,15 +144,13 @@
* @return Whether the period has passed.
*/
public boolean advanceIfElapsed(double seconds) {
- synchronized (m_lock) {
- if (get() > seconds) {
- // Advance the start time by the period.
- // Don't set it to the current time... we want to avoid drift.
- m_startTime += seconds * 1000;
- return true;
- } else {
- return false;
- }
+ if (get() >= seconds) {
+ // Advance the start time by the period.
+ // Don't set it to the current time... we want to avoid drift.
+ m_startTime += seconds * 1000;
+ return true;
+ } else {
+ return false;
}
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimesliceRobot.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimesliceRobot.java
new file mode 100644
index 0000000..5d10bb5
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/TimesliceRobot.java
@@ -0,0 +1,116 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+/**
+ * TimesliceRobot extends the TimedRobot robot program framework to provide timeslice scheduling of
+ * periodic functions.
+ *
+ * <p>The TimesliceRobot class is intended to be subclassed by a user creating a robot program.
+ *
+ * <p>This class schedules robot operations serially in a timeslice format. TimedRobot's periodic
+ * functions are the first in the timeslice table with 0 ms offset and 20 ms period. You can
+ * schedule additional controller periodic functions at a shorter period (5 ms by default). You give
+ * each one a timeslice duration, then they're run sequentially. The main benefit of this approach
+ * is consistent starting times for each controller periodic, which can make odometry and estimators
+ * more accurate and controller outputs change more consistently.
+ *
+ * <p>Here's an example of measured subsystem durations and their timeslice allocations:
+ *
+ * <table>
+ * <tr>
+ * <td><b>Subsystem</b></td>
+ * <td><b>Duration (ms)</b></td>
+ * <td><b>Allocation (ms)</b></td>
+ * </tr>
+ * <tr>
+ * <td><b>Total</b></td>
+ * <td>5.0</td>
+ * <td>5.0</td>
+ * </tr>
+ * <tr>
+ * <td>TimedRobot</td>
+ * <td>?</td>
+ * <td>2.0</td>
+ * </tr>
+ * <tr>
+ * <td>Drivetrain</td>
+ * <td>1.32</td>
+ * <td>1.5</td>
+ * </tr>
+ * <tr>
+ * <td>Flywheel</td>
+ * <td>0.6</td>
+ * <td>0.7</td>
+ * </tr>
+ * <tr>
+ * <td>Turret</td>
+ * <td>0.6</td>
+ * <td>0.8</td>
+ * </tr>
+ * <tr>
+ * <td><b>Free</b></td>
+ * <td>0.0</td>
+ * <td>N/A</td>
+ * </tr>
+ * </table>
+ *
+ * <p>Since TimedRobot periodic functions only run every 20ms, that leaves a 2 ms empty spot in the
+ * allocation table for three of the four 5 ms cycles comprising 20 ms. That's OK because the OS
+ * needs time to do other things.
+ *
+ * <p>If the robot periodic functions and the controller periodic functions have a lot of scheduling
+ * jitter that cause them to occasionally overlap with later timeslices, consider giving the main
+ * robot thread a real-time priority using {@link Threads#setCurrentThreadPriority(boolean,int)}. An
+ * RT priority of 15 is a reasonable choice.
+ *
+ * <p>If you do enable RT though, <i>make sure your periodic functions do not block</i>. If they do,
+ * the operating system will lock up, and you'll have to boot the roboRIO into safe mode and delete
+ * the robot program to recover.
+ */
+public class TimesliceRobot extends TimedRobot {
+ /**
+ * Constructor for TimesliceRobot.
+ *
+ * @param robotPeriodicAllocation The allocation in seconds to give the TimesliceRobot periodic
+ * functions.
+ * @param controllerPeriod The controller period in seconds. The sum of all scheduler allocations
+ * should be less than or equal to this value.
+ */
+ public TimesliceRobot(double robotPeriodicAllocation, double controllerPeriod) {
+ m_nextOffset = robotPeriodicAllocation;
+ m_controllerPeriod = controllerPeriod;
+ }
+
+ /**
+ * Schedule a periodic function with the constructor's controller period and the given allocation.
+ * The function's runtime allocation will be placed after the end of the previous one's.
+ *
+ * <p>If a call to this function makes the allocations exceed the controller period, an exception
+ * will be thrown since that means the TimesliceRobot periodic functions and the given function
+ * will have conflicting timeslices.
+ *
+ * @param func Function to schedule.
+ * @param allocation The function's runtime allocation in seconds out of the controller period.
+ */
+ public void schedule(Runnable func, double allocation) {
+ if (m_nextOffset + allocation > m_controllerPeriod) {
+ throw new IllegalStateException(
+ "Function scheduled at offset "
+ + m_nextOffset
+ + " with allocation "
+ + allocation
+ + " exceeded controller period of "
+ + m_controllerPeriod
+ + "\n");
+ }
+
+ addPeriodic(func, m_controllerPeriod, m_nextOffset);
+ m_nextOffset += allocation;
+ }
+
+ private double m_nextOffset;
+ private final double m_controllerPeriod;
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Tracer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Tracer.java
index 3026e90..ea04192 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Tracer.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Tracer.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -12,12 +9,12 @@
import java.util.function.Consumer;
/**
- * A class for keeping track of how much time it takes for different parts of code to execute.
- * This is done with epochs, that are added by calls to {@link #addEpoch(String)},
- * and can be printed with a call to {@link #printEpochs()}.
+ * A class for keeping track of how much time it takes for different parts of code to execute. This
+ * is done with epochs, that are added by calls to {@link #addEpoch(String)}, and can be printed
+ * with a call to {@link #printEpochs()}.
*
- * <p>Epochs are a way to partition the time elapsed so that when overruns occur, one can
- * determine which parts of an operation consumed the most time.
+ * <p>Epochs are a way to partition the time elapsed so that when overruns occur, one can determine
+ * which parts of an operation consumed the most time.
*/
public class Tracer {
private static final long kMinPrintPeriod = 1000000; // microseconds
@@ -28,24 +25,18 @@
@SuppressWarnings("PMD.UseConcurrentHashMap")
private final Map<String, Long> m_epochs = new HashMap<>(); // microseconds
- /**
- * Tracer constructor.
- */
+ /** Tracer constructor. */
public Tracer() {
resetTimer();
}
- /**
- * Clears all epochs.
- */
+ /** Clears all epochs. */
public void clearEpochs() {
m_epochs.clear();
resetTimer();
}
- /**
- * Restarts the epoch timer.
- */
+ /** Restarts the epoch timer. */
public void resetTimer() {
m_startTime = RobotController.getFPGATime();
}
@@ -56,8 +47,8 @@
* <p>Epochs are a way to partition the time elapsed so that when overruns occur, one can
* determine which parts of an operation consumed the most time.
*
- * <p>This should be called immediately after execution has finished,
- * with a call to this method or {@link #resetTimer()} before execution.
+ * <p>This should be called immediately after execution has finished, with a call to this method
+ * or {@link #resetTimer()} before execution.
*
* @param epochName The name to associate with the epoch.
*/
@@ -67,9 +58,7 @@
m_startTime = currentTime;
}
- /**
- * Prints list of epochs added so far and their times to the DriverStation.
- */
+ /** Prints list of epochs added so far and their times to the DriverStation. */
public void printEpochs() {
printEpochs(out -> DriverStation.reportWarning(out, false));
}
@@ -86,9 +75,10 @@
if (now - m_lastEpochsPrintTime > kMinPrintPeriod) {
StringBuilder sb = new StringBuilder();
m_lastEpochsPrintTime = now;
- m_epochs.forEach((key, value) -> {
- sb.append(String.format("\t%s: %.6fs\n", key, value / 1.0e6));
- });
+ m_epochs.forEach(
+ (key, value) -> {
+ sb.append(String.format("\t%s: %.6fs\n", key, value / 1.0e6));
+ });
if (sb.length() > 0) {
output.accept(sb.toString());
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Ultrasonic.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Ultrasonic.java
index 0e14c96..2d3fb4e 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Ultrasonic.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Ultrasonic.java
@@ -1,24 +1,22 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.ArrayList;
-import java.util.List;
+import static java.util.Objects.requireNonNull;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.SimBoolean;
import edu.wpi.first.hal.SimDevice;
+import edu.wpi.first.hal.SimDevice.Direction;
import edu.wpi.first.hal.SimDouble;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-import static java.util.Objects.requireNonNull;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
+import java.util.ArrayList;
+import java.util.List;
/**
* Ultrasonic rangefinder class. The Ultrasonic rangefinder measures absolute distance based on the
@@ -29,21 +27,7 @@
* echo is received. The time that the line is high determines the round trip distance (time of
* flight).
*/
-public class Ultrasonic implements PIDSource, Sendable, AutoCloseable {
- /**
- * The units to return when PIDGet is called.
- */
- public enum Unit {
- /**
- * Use inches for PIDGet.
- */
- kInches,
- /**
- * Use millimeters for PIDGet.
- */
- kMillimeters
- }
-
+public class Ultrasonic implements Sendable, AutoCloseable {
// Time (sec) for the ping trigger pulse.
private static final double kPingTime = 10 * 1e-6;
private static final double kSpeedOfSoundInchesPerSec = 1130.0 * 12.0;
@@ -53,14 +37,12 @@
private static volatile boolean m_automaticEnabled;
private DigitalInput m_echoChannel;
private DigitalOutput m_pingChannel;
- private boolean m_allocatedChannels;
+ private final boolean m_allocatedChannels;
private boolean m_enabled;
private Counter m_counter;
// task doing the round-robin automatic sensing
private static Thread m_task;
- private Unit m_units;
private static int m_instances;
- protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
private SimDevice m_simDevice;
private SimBoolean m_simRangeValid;
@@ -79,16 +61,16 @@
@Override
public synchronized void run() {
while (m_automaticEnabled) {
- for (Ultrasonic sensor: m_sensors) {
+ for (Ultrasonic sensor : m_sensors) {
if (!m_automaticEnabled) {
break;
}
if (sensor.isEnabled()) {
- sensor.m_pingChannel.pulse(kPingTime); // do the ping
+ sensor.m_pingChannel.pulse(kPingTime); // do the ping
}
- Timer.delay(0.1); // wait for ping to return
+ Timer.delay(0.1); // wait for ping to return
}
}
}
@@ -103,8 +85,8 @@
private synchronized void initialize() {
m_simDevice = SimDevice.create("Ultrasonic", m_echoChannel.getChannel());
if (m_simDevice != null) {
- m_simRangeValid = m_simDevice.createBoolean("Range Valid", false, true);
- m_simRange = m_simDevice.createDouble("Range (in)", false, 0.0);
+ m_simRangeValid = m_simDevice.createBoolean("Range Valid", Direction.kInput, true);
+ m_simRange = m_simDevice.createDouble("Range (in)", Direction.kInput, 0.0);
m_pingChannel.setSimDevice(m_simDevice);
m_echoChannel.setSimDevice(m_simDevice);
}
@@ -129,76 +111,47 @@
SendableRegistry.addLW(this, "Ultrasonic", m_echoChannel.getChannel());
}
+ public int getEchoChannel() {
+ return m_echoChannel.getChannel();
+ }
+
/**
* Create an instance of the Ultrasonic Sensor. This is designed to supchannel the Daventech SRF04
* and Vex ultrasonic sensors.
*
* @param pingChannel The digital output channel that sends the pulse to initiate the sensor
- * sending the ping.
+ * sending the ping.
* @param echoChannel The digital input channel that receives the echo. The length of time that
- * the echo is high represents the round trip time of the ping, and the
- * distance.
- * @param units The units returned in either kInches or kMilliMeters
+ * the echo is high represents the round trip time of the ping, and the distance.
*/
- public Ultrasonic(final int pingChannel, final int echoChannel, Unit units) {
+ public Ultrasonic(final int pingChannel, final int echoChannel) {
m_pingChannel = new DigitalOutput(pingChannel);
m_echoChannel = new DigitalInput(echoChannel);
SendableRegistry.addChild(this, m_pingChannel);
SendableRegistry.addChild(this, m_echoChannel);
m_allocatedChannels = true;
- m_units = units;
initialize();
}
/**
- * Create an instance of the Ultrasonic Sensor. This is designed to supchannel the Daventech SRF04
- * and Vex ultrasonic sensors. Default unit is inches.
- *
- * @param pingChannel The digital output channel that sends the pulse to initiate the sensor
- * sending the ping.
- * @param echoChannel The digital input channel that receives the echo. The length of time that
- * the echo is high represents the round trip time of the ping, and the
- * distance.
- */
- public Ultrasonic(final int pingChannel, final int echoChannel) {
- this(pingChannel, echoChannel, Unit.kInches);
- }
-
- /**
* Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo channel and a
* DigitalOutput for the ping channel.
*
* @param pingChannel The digital output object that starts the sensor doing a ping. Requires a
- * 10uS pulse to start.
- * @param echoChannel The digital input object that times the return pulse to determine the
- * range.
- * @param units The units returned in either kInches or kMilliMeters
+ * 10uS pulse to start.
+ * @param echoChannel The digital input object that times the return pulse to determine the range.
*/
- public Ultrasonic(DigitalOutput pingChannel, DigitalInput echoChannel, Unit units) {
+ public Ultrasonic(DigitalOutput pingChannel, DigitalInput echoChannel) {
requireNonNull(pingChannel, "Provided ping channel was null");
requireNonNull(echoChannel, "Provided echo channel was null");
m_allocatedChannels = false;
m_pingChannel = pingChannel;
m_echoChannel = echoChannel;
- m_units = units;
initialize();
}
/**
- * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo channel and a
- * DigitalOutput for the ping channel. Default unit is inches.
- *
- * @param pingChannel The digital output object that starts the sensor doing a ping. Requires a
- * 10uS pulse to start.
- * @param echoChannel The digital input object that times the return pulse to determine the
- * range.
- */
- public Ultrasonic(DigitalOutput pingChannel, DigitalInput echoChannel) {
- this(pingChannel, echoChannel, Unit.kInches);
- }
-
- /**
* Destructor for the ultrasonic sensor. Delete the instance of the ultrasonic sensor by freeing
* the allocated digital channels. If the system was in automatic mode (round robin), then it is
* stopped, then started again after this sensor is removed (provided this wasn't the last
@@ -245,10 +198,9 @@
* each sensor.
*
* @param enabling Set to true if round robin scheduling should start for all the ultrasonic
- * sensors. This scheduling method assures that the sensors are non-interfering
- * because no two sensors fire at the same time. If another scheduling algorithm
- * is preferred, it can be implemented by pinging the sensors manually and waiting
- * for the results to come back.
+ * sensors. This scheduling method assures that the sensors are non-interfering because no two
+ * sensors fire at the same time. If another scheduling algorithm is preferred, it can be
+ * implemented by pinging the sensors manually and waiting for the results to come back.
*/
public static void setAutomaticMode(boolean enabling) {
if (enabling == m_automaticEnabled) {
@@ -340,54 +292,6 @@
return getRangeInches() * 25.4;
}
- @Override
- public void setPIDSourceType(PIDSourceType pidSource) {
- if (!pidSource.equals(PIDSourceType.kDisplacement)) {
- throw new IllegalArgumentException("Only displacement PID is allowed for ultrasonics.");
- }
- m_pidSource = pidSource;
- }
-
- @Override
- public PIDSourceType getPIDSourceType() {
- return m_pidSource;
- }
-
- /**
- * Get the range in the current DistanceUnit for the PIDSource base object.
- *
- * @return The range in DistanceUnit
- */
- @Override
- public double pidGet() {
- switch (m_units) {
- case kInches:
- return getRangeInches();
- case kMillimeters:
- return getRangeMM();
- default:
- return 0.0;
- }
- }
-
- /**
- * Set the current DistanceUnit that should be used for the PIDSource base object.
- *
- * @param units The DistanceUnit that should be used.
- */
- public void setDistanceUnits(Unit units) {
- m_units = units;
- }
-
- /**
- * Get the current DistanceUnit that is used for the PIDSource base object.
- *
- * @return The type of DistanceUnit that is being used.
- */
- public Unit getDistanceUnits() {
- return m_units;
- }
-
/**
* Is the ultrasonic enabled.
*
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Victor.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Victor.java
deleted file mode 100644
index 29c1b27..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Victor.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * VEX Robotics Victor 888 Speed Controller The Vex Robotics Victor 884 Speed Controller can also
- * be used with this class but may need to be calibrated per the Victor 884 user manual.
- *
- * <p>Note that the Victor uses the following bounds for PWM values. These values were determined
- * empirically and optimized for the Victor 888. These values should work reasonably well for
- * Victor 884 controllers also but if users experience issues such as asymmetric behavior around
- * the deadband or inability to saturate the controller in either direction, calibration is
- * recommended. The calibration procedure can be found in the Victor 884 User Manual available
- * from VEX Robotics: http://content.vexrobotics.com/docs/ifi-v884-users-manual-9-25-06.pdf
- *
- * <p><ul>
- * <li>2.027ms = full "forward"
- * <li>1.525ms = the "high end" of the deadband range
- * <li>1.507ms = center of the deadband range (off)
- * <li>1.490ms = the "low end" of the deadband range
- * <li>1.026ms = full "reverse"
- * </ul>
- */
-public class Victor extends PWMSpeedController {
- /**
- * Constructor.
- *
- * @param channel The PWM channel that the Victor is attached to. 0-9 are
- * on-board, 10-19 are on the MXP port
- */
- public Victor(final int channel) {
- super(channel);
-
- setBounds(2.027, 1.525, 1.507, 1.49, 1.026);
- setPeriodMultiplier(PeriodMultiplier.k2X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_Victor, getChannel() + 1);
- SendableRegistry.setName(this, "Victor", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/VictorSP.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/VictorSP.java
deleted file mode 100644
index 22b3513..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/VictorSP.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * VEX Robotics Victor SP Speed Controller.
- *
- * <p>Note that the VictorSP uses the following bounds for PWM values. These values should work
- * reasonably well for most controllers, but if users experience issues such as asymmetric
- * behavior around the deadband or inability to saturate the controller in either direction,
- * calibration is recommended. The calibration procedure can be found in the VictorSP User Manual
- * available from CTRE.
- *
- * <p><ul>
- * <li>2.004ms = full "forward"
- * <li>1.520ms = the "high end" of the deadband range
- * <li>1.500ms = center of the deadband range (off)
- * <li>1.480ms = the "low end" of the deadband range
- * <li>0.997ms = full "reverse"
- * </ul>
- */
-public class VictorSP extends PWMSpeedController {
- /**
- * Constructor.
- *
- * @param channel The PWM channel that the VictorSP is attached to. 0-9 are
- * on-board, 10-19 are on the MXP port
- */
- public VictorSP(final int channel) {
- super(channel);
-
- setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
- setPeriodMultiplier(PeriodMultiplier.k1X);
- setSpeed(0.0);
- setZeroLatch();
-
- HAL.report(tResourceType.kResourceType_VictorSP, getChannel() + 1);
- SendableRegistry.setName(this, "VictorSP", getChannel());
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Watchdog.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Watchdog.java
index aaf5671..22581a5 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/Watchdog.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/Watchdog.java
@@ -1,18 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+import edu.wpi.first.hal.NotifierJNI;
import java.io.Closeable;
import java.util.PriorityQueue;
import java.util.concurrent.locks.ReentrantLock;
-import edu.wpi.first.hal.NotifierJNI;
-
/**
* A class that's a wrapper around a watchdog timer.
*
@@ -23,13 +19,13 @@
*/
public class Watchdog implements Closeable, Comparable<Watchdog> {
// Used for timeout print rate-limiting
- private static final long kMinPrintPeriod = 1000000; // microseconds
+ private static final long kMinPrintPeriodMicroS = (long) 1e6;
- private double m_startTime; // seconds
- private double m_timeout; // seconds
- private double m_expirationTime; // seconds
+ private double m_startTimeSeconds;
+ private double m_timeoutSeconds;
+ private double m_expirationTimeSeconds;
private final Runnable m_callback;
- private double m_lastTimeoutPrintTime; // seconds
+ private double m_lastTimeoutPrintSeconds;
boolean m_isExpired;
@@ -50,11 +46,11 @@
/**
* Watchdog constructor.
*
- * @param timeout The watchdog's timeout in seconds with microsecond resolution.
+ * @param timeoutSeconds The watchdog's timeout in seconds with microsecond resolution.
* @param callback This function is called when the timeout expires.
*/
- public Watchdog(double timeout, Runnable callback) {
- m_timeout = timeout;
+ public Watchdog(double timeoutSeconds, Runnable callback) {
+ m_timeoutSeconds = timeoutSeconds;
m_callback = callback;
m_tracer = new Tracer();
}
@@ -65,50 +61,50 @@
}
@Override
- public int compareTo(Watchdog rhs) {
- // Elements with sooner expiration times are sorted as lesser. The head of
- // Java's PriorityQueue is the least element.
- return Double.compare(m_expirationTime, rhs.m_expirationTime);
- }
-
- @Override
public boolean equals(Object obj) {
- if (!(obj instanceof Watchdog)) {
- return false;
+ if (obj instanceof Watchdog) {
+ return Double.compare(m_expirationTimeSeconds, ((Watchdog) obj).m_expirationTimeSeconds) == 0;
}
- Watchdog oth = (Watchdog) obj;
- return oth.m_expirationTime == m_expirationTime;
+ return false;
}
@Override
public int hashCode() {
- return Double.hashCode(m_expirationTime);
+ return Double.hashCode(m_expirationTimeSeconds);
+ }
+
+ @Override
+ public int compareTo(Watchdog rhs) {
+ // Elements with sooner expiration times are sorted as lesser. The head of
+ // Java's PriorityQueue is the least element.
+ return Double.compare(m_expirationTimeSeconds, rhs.m_expirationTimeSeconds);
}
/**
* Returns the time in seconds since the watchdog was last fed.
+ *
+ * @return The time in seconds since the watchdog was last fed.
*/
public double getTime() {
- return Timer.getFPGATimestamp() - m_startTime;
+ return Timer.getFPGATimestamp() - m_startTimeSeconds;
}
/**
* Sets the watchdog's timeout.
*
- * @param timeout The watchdog's timeout in seconds with microsecond
- * resolution.
+ * @param timeoutSeconds The watchdog's timeout in seconds with microsecond resolution.
*/
- public void setTimeout(double timeout) {
- m_startTime = Timer.getFPGATimestamp();
+ public void setTimeout(double timeoutSeconds) {
+ m_startTimeSeconds = Timer.getFPGATimestamp();
m_tracer.clearEpochs();
m_queueMutex.lock();
try {
- m_timeout = timeout;
+ m_timeoutSeconds = timeoutSeconds;
m_isExpired = false;
m_watchdogs.remove(this);
- m_expirationTime = m_startTime + m_timeout;
+ m_expirationTimeSeconds = m_startTimeSeconds + m_timeoutSeconds;
m_watchdogs.add(this);
updateAlarm();
} finally {
@@ -118,11 +114,13 @@
/**
* Returns the watchdog's timeout in seconds.
+ *
+ * @return The watchdog's timeout in seconds.
*/
public double getTimeout() {
m_queueMutex.lock();
try {
- return m_timeout;
+ return m_timeoutSeconds;
} finally {
m_queueMutex.unlock();
}
@@ -130,6 +128,8 @@
/**
* Returns true if the watchdog timer has expired.
+ *
+ * @return True if the watchdog timer has expired.
*/
public boolean isExpired() {
m_queueMutex.lock();
@@ -144,7 +144,6 @@
* Adds time since last epoch to the list printed by printEpochs().
*
* @see Tracer#addEpoch(String)
- *
* @param epochName The name to associate with the epoch.
*/
public void addEpoch(String epochName) {
@@ -153,6 +152,7 @@
/**
* Prints list of epochs added so far and their times.
+ *
* @see Tracer#printEpochs()
*/
public void printEpochs() {
@@ -168,11 +168,9 @@
enable();
}
- /**
- * Enables the watchdog timer.
- */
+ /** Enables the watchdog timer. */
public void enable() {
- m_startTime = Timer.getFPGATimestamp();
+ m_startTimeSeconds = Timer.getFPGATimestamp();
m_tracer.clearEpochs();
m_queueMutex.lock();
@@ -180,7 +178,7 @@
m_isExpired = false;
m_watchdogs.remove(this);
- m_expirationTime = m_startTime + m_timeout;
+ m_expirationTimeSeconds = m_startTimeSeconds + m_timeoutSeconds;
m_watchdogs.add(this);
updateAlarm();
} finally {
@@ -188,9 +186,7 @@
}
}
- /**
- * Disables the watchdog timer.
- */
+ /** Disables the watchdog timer. */
public void disable() {
m_queueMutex.lock();
try {
@@ -212,12 +208,13 @@
m_suppressTimeoutMessage = suppress;
}
+ @SuppressWarnings("resource")
private static void updateAlarm() {
if (m_watchdogs.size() == 0) {
NotifierJNI.cancelNotifierAlarm(m_notifier);
} else {
- NotifierJNI.updateNotifierAlarm(m_notifier,
- (long) (m_watchdogs.peek().m_expirationTime * 1e6));
+ NotifierJNI.updateNotifierAlarm(
+ m_notifier, (long) (m_watchdogs.peek().m_expirationTimeSeconds * 1e6));
}
}
@@ -247,12 +244,11 @@
Watchdog watchdog = m_watchdogs.poll();
double now = curTime * 1e-6;
- if (now - watchdog.m_lastTimeoutPrintTime > kMinPrintPeriod) {
- watchdog.m_lastTimeoutPrintTime = now;
+ if (now - watchdog.m_lastTimeoutPrintSeconds > kMinPrintPeriodMicroS) {
+ watchdog.m_lastTimeoutPrintSeconds = now;
if (!watchdog.m_suppressTimeoutMessage) {
DriverStation.reportWarning(
- String.format("Watchdog not fed within %.6fs\n", watchdog.m_timeout),
- false);
+ String.format("Watchdog not fed within %.6fs\n", watchdog.m_timeoutSeconds), false);
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/XboxController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/XboxController.java
index 6248a76..5de3503 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/XboxController.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/XboxController.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
@@ -18,14 +15,12 @@
* and the mapping of ports to hardware buttons depends on the code in the Driver Station.
*/
public class XboxController extends GenericHID {
- /**
- * Represents a digital button on an XboxController.
- */
+ /** Represents a digital button on an XboxController. */
public enum Button {
- kBumperLeft(5),
- kBumperRight(6),
- kStickLeft(9),
- kStickRight(10),
+ kLeftBumper(5),
+ kRightBumper(6),
+ kLeftStick(9),
+ kRightStick(10),
kA(1),
kB(2),
kX(3),
@@ -33,17 +28,32 @@
kBack(7),
kStart(8);
- @SuppressWarnings({"MemberName", "PMD.SingularField"})
+ @SuppressWarnings("MemberName")
public final int value;
Button(int value) {
this.value = value;
}
+
+ /**
+ * Get the human-friendly name of the button, matching the relevant methods. This is done by
+ * stripping the leading `k`, and if not a Bumper button append `Button`.
+ *
+ * <p>Primarily used for automated unit tests.
+ *
+ * @return the human-friendly name of the button.
+ */
+ @Override
+ public String toString() {
+ var name = this.name().substring(1); // Remove leading `k`
+ if (name.endsWith("Bumper")) {
+ return name;
+ }
+ return name + "Button";
+ }
}
- /**
- * Represents an axis on an XboxController.
- */
+ /** Represents an axis on an XboxController. */
public enum Axis {
kLeftX(0),
kRightX(4),
@@ -52,19 +62,35 @@
kLeftTrigger(2),
kRightTrigger(3);
- @SuppressWarnings({"MemberName", "PMD.SingularField"})
+ @SuppressWarnings("MemberName")
public final int value;
Axis(int value) {
this.value = value;
}
+
+ /**
+ * Get the human-friendly name of the axis, matching the relevant methods. This is done by
+ * stripping the leading `k`, and if a trigger axis append `Axis`.
+ *
+ * <p>Primarily used for automated unit tests.
+ *
+ * @return the human-friendly name of the axis.
+ */
+ @Override
+ public String toString() {
+ var name = this.name().substring(1); // Remove leading `k`
+ if (name.endsWith("Trigger")) {
+ return name + "Axis";
+ }
+ return name;
+ }
}
/**
- * Construct an instance of a joystick. The joystick index is the USB port on the drivers
- * station.
+ * Construct an instance of a controller.
*
- * @param port The port on the Driver Station that the joystick is plugged into.
+ * @param port The port index on the Driver Station that the controller is plugged into.
*/
public XboxController(final int port) {
super(port);
@@ -73,131 +99,167 @@
}
/**
- * Get the X axis value of the controller.
+ * Get the X axis value of left side of the controller.
*
- * @param hand Side of controller whose value should be returned.
- * @return The X axis value of the controller.
+ * @return The axis value.
*/
- @Override
- public double getX(Hand hand) {
- if (hand.equals(Hand.kLeft)) {
- return getRawAxis(Axis.kLeftX.value);
- } else {
- return getRawAxis(Axis.kRightX.value);
- }
+ public double getLeftX() {
+ return getRawAxis(Axis.kLeftX.value);
}
/**
- * Get the Y axis value of the controller.
+ * Get the X axis value of right side of the controller.
*
- * @param hand Side of controller whose value should be returned.
- * @return The Y axis value of the controller.
+ * @return The axis value.
*/
- @Override
- public double getY(Hand hand) {
- if (hand.equals(Hand.kLeft)) {
- return getRawAxis(Axis.kLeftY.value);
- } else {
- return getRawAxis(Axis.kRightY.value);
- }
+ public double getRightX() {
+ return getRawAxis(Axis.kRightX.value);
}
/**
- * Get the trigger axis value of the controller.
+ * Get the Y axis value of left side of the controller.
*
- * @param hand Side of controller whose value should be returned.
- * @return The trigger axis value of the controller.
+ * @return The axis value.
*/
- public double getTriggerAxis(Hand hand) {
- if (hand.equals(Hand.kLeft)) {
- return getRawAxis(Axis.kLeftTrigger.value);
- } else {
- return getRawAxis(Axis.kRightTrigger.value);
- }
+ public double getLeftY() {
+ return getRawAxis(Axis.kLeftY.value);
}
/**
- * Read the value of the bumper button on the controller.
+ * Get the Y axis value of right side of the controller.
*
- * @param hand Side of controller whose value should be returned.
+ * @return The axis value.
+ */
+ public double getRightY() {
+ return getRawAxis(Axis.kRightY.value);
+ }
+
+ /**
+ * Get the left trigger (LT) 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 getLeftTriggerAxis() {
+ return getRawAxis(Axis.kLeftTrigger.value);
+ }
+
+ /**
+ * Get the right trigger (RT) 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 getRightTriggerAxis() {
+ return getRawAxis(Axis.kRightTrigger.value);
+ }
+
+ /**
+ * Read the value of the left bumper (LB) button on the controller.
+ *
* @return The state of the button.
*/
- public boolean getBumper(Hand hand) {
- if (hand.equals(Hand.kLeft)) {
- return getRawButton(Button.kBumperLeft.value);
- } else {
- return getRawButton(Button.kBumperRight.value);
- }
+ public boolean getLeftBumper() {
+ return getRawButton(Button.kLeftBumper.value);
}
/**
- * Whether the bumper was pressed since the last check.
+ * Read the value of the right bumper (RB) button on the controller.
*
- * @param hand Side of controller whose value should be returned.
- * @return Whether the button was pressed since the last check.
- */
- public boolean getBumperPressed(Hand hand) {
- if (hand == Hand.kLeft) {
- return getRawButtonPressed(Button.kBumperLeft.value);
- } else {
- return getRawButtonPressed(Button.kBumperRight.value);
- }
- }
-
- /**
- * Whether the bumper was released since the last check.
- *
- * @param hand Side of controller whose value should be returned.
- * @return Whether the button was released since the last check.
- */
- public boolean getBumperReleased(Hand hand) {
- if (hand == Hand.kLeft) {
- return getRawButtonReleased(Button.kBumperLeft.value);
- } else {
- return getRawButtonReleased(Button.kBumperRight.value);
- }
- }
-
- /**
- * Read the value of the stick button on the controller.
- *
- * @param hand Side of controller whose value should be returned.
* @return The state of the button.
*/
- public boolean getStickButton(Hand hand) {
- if (hand.equals(Hand.kLeft)) {
- return getRawButton(Button.kStickLeft.value);
- } else {
- return getRawButton(Button.kStickRight.value);
- }
+ public boolean getRightBumper() {
+ return getRawButton(Button.kRightBumper.value);
}
/**
- * Whether the stick button was pressed since the last check.
+ * Whether the left bumper (LB) was pressed since the last check.
*
- * @param hand Side of controller whose value should be returned.
* @return Whether the button was pressed since the last check.
*/
- public boolean getStickButtonPressed(Hand hand) {
- if (hand == Hand.kLeft) {
- return getRawButtonPressed(Button.kStickLeft.value);
- } else {
- return getRawButtonPressed(Button.kStickRight.value);
- }
+ public boolean getLeftBumperPressed() {
+ return getRawButtonPressed(Button.kLeftBumper.value);
}
/**
- * Whether the stick button was released since the last check.
+ * Whether the right bumper (RB) was pressed since the last check.
*
- * @param hand Side of controller whose value should be returned.
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getRightBumperPressed() {
+ return getRawButtonPressed(Button.kRightBumper.value);
+ }
+
+ /**
+ * Whether the left bumper (LB) was released since the last check.
+ *
* @return Whether the button was released since the last check.
*/
- public boolean getStickButtonReleased(Hand hand) {
- if (hand == Hand.kLeft) {
- return getRawButtonReleased(Button.kStickLeft.value);
- } else {
- return getRawButtonReleased(Button.kStickRight.value);
- }
+ public boolean getLeftBumperReleased() {
+ return getRawButtonReleased(Button.kLeftBumper.value);
+ }
+
+ /**
+ * Whether the right bumper (RB) was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getRightBumperReleased() {
+ return getRawButtonReleased(Button.kRightBumper.value);
+ }
+
+ /**
+ * Read the value of the left stick button (LSB) on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getLeftStickButton() {
+ return getRawButton(Button.kLeftStick.value);
+ }
+
+ /**
+ * Read the value of the right stick button (RSB) on the controller.
+ *
+ * @return The state of the button.
+ */
+ public boolean getRightStickButton() {
+ return getRawButton(Button.kRightStick.value);
+ }
+
+ /**
+ * Whether the left stick button (LSB) was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getLeftStickButtonPressed() {
+ return getRawButtonPressed(Button.kLeftStick.value);
+ }
+
+ /**
+ * Whether the right stick button (RSB) was pressed since the last check.
+ *
+ * @return Whether the button was pressed since the last check.
+ */
+ public boolean getRightStickButtonPressed() {
+ return getRawButtonPressed(Button.kRightStick.value);
+ }
+
+ /**
+ * Whether the left stick button (LSB) was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getLeftStickButtonReleased() {
+ return getRawButtonReleased(Button.kLeftStick.value);
+ }
+
+ /**
+ * Whether the right stick (RSB) button was released since the last check.
+ *
+ * @return Whether the button was released since the last check.
+ */
+ public boolean getRightStickButtonReleased() {
+ return getRawButtonReleased(Button.kRightStick.value);
}
/**
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/ControllerUtil.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/ControllerUtil.java
deleted file mode 100644
index 0896ac6..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/ControllerUtil.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-public final class ControllerUtil {
- /**
- * Returns modulus of error where error is the difference between the reference
- * and a measurement.
- *
- * @param reference Reference input of a controller.
- * @param measurement The current measurement.
- * @param minimumInput The minimum value expected from the input.
- * @param maximumInput The maximum value expected from the input.
- */
- public static double getModulusError(double reference, double measurement, double minimumInput,
- double maximumInput) {
- double error = reference - measurement;
- double modulus = maximumInput - minimumInput;
-
- // Wrap error above maximum input
- int numMax = (int) ((error + maximumInput) / modulus);
- error -= numMax * modulus;
-
- // Wrap error below minimum input
- int numMin = (int) ((error + minimumInput) / modulus);
- error -= numMin * modulus;
-
- return error;
- }
-
- private ControllerUtil() {
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/HolonomicDriveController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/HolonomicDriveController.java
deleted file mode 100644
index 4a98232..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/HolonomicDriveController.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import edu.wpi.first.wpilibj.geometry.Pose2d;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
-import edu.wpi.first.wpilibj.kinematics.ChassisSpeeds;
-import edu.wpi.first.wpilibj.trajectory.Trajectory;
-
-/**
- * This holonomic drive controller can be used to follow trajectories using a
- * holonomic drive train (i.e. swerve or mecanum). Holonomic trajectory following
- * is a much simpler problem to solve compared to skid-steer style drivetrains because
- * it is possible to individually control forward, sideways, and angular velocity.
- *
- * <p>The holonomic drive controller takes in one PID controller for each direction, forward
- * and sideways, and one profiled PID controller for the angular direction. Because the
- * heading dynamics are decoupled from translations, users can specify a custom heading
- * that the drivetrain should point toward. This heading reference is profiled for smoothness.
- */
-@SuppressWarnings("MemberName")
-public class HolonomicDriveController {
- private Pose2d m_poseError = new Pose2d();
- private Pose2d m_poseTolerance = new Pose2d();
- private boolean m_enabled = true;
-
- private final PIDController m_xController;
- private final PIDController m_yController;
- private final ProfiledPIDController m_thetaController;
-
- /**
- * Constructs a holonomic drive controller.
- *
- * @param xController A PID Controller to respond to error in the field-relative x direction.
- * @param yController A PID Controller to respond to error in the field-relative y direction.
- * @param thetaController A profiled PID controller to respond to error in angle.
- */
- @SuppressWarnings("ParameterName")
- public HolonomicDriveController(PIDController xController,
- PIDController yController,
- ProfiledPIDController thetaController) {
- m_xController = xController;
- m_yController = yController;
- m_thetaController = thetaController;
- }
-
- /**
- * Returns true if the pose error is within tolerance of the reference.
- *
- * @return True if the pose error is within tolerance of the reference.
- */
- public boolean atReference() {
- final var eTranslate = m_poseError.getTranslation();
- final var eRotate = m_poseError.getRotation();
- final var tolTranslate = m_poseTolerance.getTranslation();
- final var tolRotate = m_poseTolerance.getRotation();
- return Math.abs(eTranslate.getX()) < tolTranslate.getX()
- && Math.abs(eTranslate.getY()) < tolTranslate.getY()
- && Math.abs(eRotate.getRadians()) < tolRotate.getRadians();
- }
-
- /**
- * Sets the pose error which is considered tolerance for use with atReference().
- *
- * @param tolerance The pose error which is tolerable.
- */
- public void setTolerance(Pose2d tolerance) {
- m_poseTolerance = tolerance;
- }
-
- /**
- * Returns the next output of the holonomic drive controller.
- *
- * @param currentPose The current pose.
- * @param poseRef The desired pose.
- * @param linearVelocityRefMeters The linear velocity reference.
- * @param angleRef The angular reference.
- * @return The next output of the holonomic drive controller.
- */
- @SuppressWarnings("LocalVariableName")
- public ChassisSpeeds calculate(Pose2d currentPose,
- Pose2d poseRef,
- double linearVelocityRefMeters,
- Rotation2d angleRef) {
- // Calculate feedforward velocities (field-relative).
- double xFF = linearVelocityRefMeters * poseRef.getRotation().getCos();
- double yFF = linearVelocityRefMeters * poseRef.getRotation().getSin();
- double thetaFF = m_thetaController.calculate(currentPose.getRotation().getRadians(),
- angleRef.getRadians());
-
- m_poseError = poseRef.relativeTo(currentPose);
-
- if (!m_enabled) {
- return ChassisSpeeds.fromFieldRelativeSpeeds(xFF, yFF, thetaFF, currentPose.getRotation());
- }
-
- // Calculate feedback velocities (based on position error).
- double xFeedback = m_xController.calculate(currentPose.getX(), poseRef.getX());
- double yFeedback = m_yController.calculate(currentPose.getY(), poseRef.getY());
-
- // Return next output.
- return ChassisSpeeds.fromFieldRelativeSpeeds(xFF + xFeedback,
- yFF + yFeedback, thetaFF, currentPose.getRotation());
- }
-
- /**
- * Returns the next output of the holonomic drive controller.
- *
- * @param currentPose The current pose.
- * @param desiredState The desired trajectory state.
- * @param angleRef The desired end-angle.
- * @return The next output of the holonomic drive controller.
- */
- public ChassisSpeeds calculate(Pose2d currentPose, Trajectory.State desiredState,
- Rotation2d angleRef) {
- return calculate(currentPose, desiredState.poseMeters, desiredState.velocityMetersPerSecond,
- angleRef);
- }
-
- /**
- * Enables and disables the controller for troubleshooting problems. When calculate()
- * is called on a disabled controller, only feedforward values are returned.
- *
- * @param enabled If the controller is enabled or not.
- */
- public void setEnabled(boolean enabled) {
- m_enabled = enabled;
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/PIDController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/PIDController.java
deleted file mode 100644
index 526e91e..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/PIDController.java
+++ /dev/null
@@ -1,351 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.Sendable;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-import edu.wpi.first.wpiutil.math.MathUtil;
-
-/**
- * Implements a PID control loop.
- */
-@SuppressWarnings("PMD.TooManyFields")
-public class PIDController implements Sendable, AutoCloseable {
- private static int instances;
-
- // Factor for "proportional" control
- @SuppressWarnings("MemberName")
- private double m_Kp;
-
- // Factor for "integral" control
- @SuppressWarnings("MemberName")
- private double m_Ki;
-
- // Factor for "derivative" control
- @SuppressWarnings("MemberName")
- private double m_Kd;
-
- // The period (in seconds) of the loop that calls the controller
- private final double m_period;
-
- private double m_maximumIntegral = 1.0;
-
- private double m_minimumIntegral = -1.0;
-
- private double m_maximumInput;
-
- private double m_minimumInput;
-
- // Do the endpoints wrap around? eg. Absolute encoder
- private boolean m_continuous;
-
- // The error at the time of the most recent call to calculate()
- private double m_positionError;
- private double m_velocityError;
-
- // The error at the time of the second-most-recent call to calculate() (used to compute velocity)
- private double m_prevError;
-
- // The sum of the errors for use in the integral calc
- private double m_totalError;
-
- // The error that is considered at setpoint.
- private double m_positionTolerance = 0.05;
- private double m_velocityTolerance = Double.POSITIVE_INFINITY;
-
- private double m_setpoint;
-
- /**
- * Allocates a PIDController with the given constants for Kp, Ki, and Kd and a default period of
- * 0.02 seconds.
- *
- * @param Kp The proportional coefficient.
- * @param Ki The integral coefficient.
- * @param Kd The derivative coefficient.
- */
- @SuppressWarnings("ParameterName")
- public PIDController(double Kp, double Ki, double Kd) {
- this(Kp, Ki, Kd, 0.02);
- }
-
- /**
- * Allocates a PIDController with the given constants for Kp, Ki, and Kd.
- *
- * @param Kp The proportional coefficient.
- * @param Ki The integral coefficient.
- * @param Kd The derivative coefficient.
- * @param period The period between controller updates in seconds.
- */
- @SuppressWarnings("ParameterName")
- public PIDController(double Kp, double Ki, double Kd, double period) {
- m_Kp = Kp;
- m_Ki = Ki;
- m_Kd = Kd;
-
- m_period = period;
-
- instances++;
- SendableRegistry.addLW(this, "PIDController", instances);
-
- HAL.report(tResourceType.kResourceType_PIDController2, instances);
- }
-
- @Override
- public void close() {
- SendableRegistry.remove(this);
- }
-
- /**
- * Sets the PID Controller gain parameters.
- *
- * <p>Set the proportional, integral, and differential coefficients.
- *
- * @param Kp The proportional coefficient.
- * @param Ki The integral coefficient.
- * @param Kd The derivative coefficient.
- */
- @SuppressWarnings("ParameterName")
- public void setPID(double Kp, double Ki, double Kd) {
- m_Kp = Kp;
- m_Ki = Ki;
- m_Kd = Kd;
- }
-
- /**
- * Sets the Proportional coefficient of the PID controller gain.
- *
- * @param Kp proportional coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setP(double Kp) {
- m_Kp = Kp;
- }
-
- /**
- * Sets the Integral coefficient of the PID controller gain.
- *
- * @param Ki integral coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setI(double Ki) {
- m_Ki = Ki;
- }
-
- /**
- * Sets the Differential coefficient of the PID controller gain.
- *
- * @param Kd differential coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setD(double Kd) {
- m_Kd = Kd;
- }
-
- /**
- * Get the Proportional coefficient.
- *
- * @return proportional coefficient
- */
- public double getP() {
- return m_Kp;
- }
-
- /**
- * Get the Integral coefficient.
- *
- * @return integral coefficient
- */
- public double getI() {
- return m_Ki;
- }
-
- /**
- * Get the Differential coefficient.
- *
- * @return differential coefficient
- */
- public double getD() {
- return m_Kd;
- }
-
- /**
- * Returns the period of this controller.
- *
- * @return the period of the controller.
- */
- public double getPeriod() {
- return m_period;
- }
-
- /**
- * Sets the setpoint for the PIDController.
- *
- * @param setpoint The desired setpoint.
- */
- public void setSetpoint(double setpoint) {
- m_setpoint = setpoint;
- }
-
- /**
- * Returns the current setpoint of the PIDController.
- *
- * @return The current setpoint.
- */
- public double getSetpoint() {
- return m_setpoint;
- }
-
- /**
- * Returns true if the error is within the tolerance of the setpoint.
- *
- * <p>This will return false until at least one input value has been computed.
- *
- * @return Whether the error is within the acceptable bounds.
- */
- public boolean atSetpoint() {
- return Math.abs(m_positionError) < m_positionTolerance
- && Math.abs(m_velocityError) < m_velocityTolerance;
- }
-
- /**
- * Enables continuous input.
- *
- * <p>Rather then using the max and min input range as constraints, it considers
- * them to be the same point and automatically calculates the shortest route
- * to the setpoint.
- *
- * @param minimumInput The minimum value expected from the input.
- * @param maximumInput The maximum value expected from the input.
- */
- public void enableContinuousInput(double minimumInput, double maximumInput) {
- m_continuous = true;
- m_minimumInput = minimumInput;
- m_maximumInput = maximumInput;
- }
-
- /**
- * Disables continuous input.
- */
- public void disableContinuousInput() {
- m_continuous = false;
- }
-
- /**
- * Returns true if continuous input is enabled.
- */
- public boolean isContinuousInputEnabled() {
- return m_continuous;
- }
-
- /**
- * Sets the minimum and maximum values for the integrator.
- *
- * <p>When the cap is reached, the integrator value is added to the controller
- * output rather than the integrator value times the integral gain.
- *
- * @param minimumIntegral The minimum value of the integrator.
- * @param maximumIntegral The maximum value of the integrator.
- */
- public void setIntegratorRange(double minimumIntegral, double maximumIntegral) {
- m_minimumIntegral = minimumIntegral;
- m_maximumIntegral = maximumIntegral;
- }
-
- /**
- * Sets the error which is considered tolerable for use with atSetpoint().
- *
- * @param positionTolerance Position error which is tolerable.
- */
- public void setTolerance(double positionTolerance) {
- setTolerance(positionTolerance, Double.POSITIVE_INFINITY);
- }
-
- /**
- * Sets the error which is considered tolerable for use with atSetpoint().
- *
- * @param positionTolerance Position error which is tolerable.
- * @param velocityTolerance Velocity error which is tolerable.
- */
- public void setTolerance(double positionTolerance, double velocityTolerance) {
- m_positionTolerance = positionTolerance;
- m_velocityTolerance = velocityTolerance;
- }
-
- /**
- * Returns the difference between the setpoint and the measurement.
- *
- * @return The error.
- */
- public double getPositionError() {
- return m_positionError;
- }
-
- /**
- * Returns the velocity error.
- */
- public double getVelocityError() {
- return m_velocityError;
- }
-
- /**
- * Returns the next output of the PID controller.
- *
- * @param measurement The current measurement of the process variable.
- * @param setpoint The new setpoint of the controller.
- */
- public double calculate(double measurement, double setpoint) {
- // Set setpoint to provided value
- setSetpoint(setpoint);
- return calculate(measurement);
- }
-
- /**
- * Returns the next output of the PID controller.
- *
- * @param measurement The current measurement of the process variable.
- */
- public double calculate(double measurement) {
- m_prevError = m_positionError;
-
- if (m_continuous) {
- m_positionError = ControllerUtil.getModulusError(m_setpoint, measurement, m_minimumInput,
- m_maximumInput);
- } else {
- m_positionError = m_setpoint - measurement;
- }
-
- m_velocityError = (m_positionError - m_prevError) / m_period;
-
- if (m_Ki != 0) {
- m_totalError = MathUtil.clamp(m_totalError + m_positionError * m_period,
- m_minimumIntegral / m_Ki, m_maximumIntegral / m_Ki);
- }
-
- return m_Kp * m_positionError + m_Ki * m_totalError + m_Kd * m_velocityError;
- }
-
- /**
- * Resets the previous error and the integral term.
- */
- public void reset() {
- m_prevError = 0;
- m_totalError = 0;
- }
-
- @Override
- public void initSendable(SendableBuilder builder) {
- builder.setSmartDashboardType("PIDController");
- builder.addDoubleProperty("p", this::getP, this::setP);
- builder.addDoubleProperty("i", this::getI, this::setI);
- builder.addDoubleProperty("d", this::getD, this::setD);
- builder.addDoubleProperty("setpoint", this::getSetpoint, this::setSetpoint);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/ProfiledPIDController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/ProfiledPIDController.java
deleted file mode 100644
index 3955c5b..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/ProfiledPIDController.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.Sendable;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.trajectory.TrapezoidProfile;
-
-/**
- * Implements a PID control loop whose setpoint is constrained by a trapezoid
- * profile. Users should call reset() when they first start running the controller
- * to avoid unwanted behavior.
- */
-public class ProfiledPIDController implements Sendable {
- private static int instances;
-
- private PIDController m_controller;
- private double m_minimumInput;
- private double m_maximumInput;
- private TrapezoidProfile.State m_goal = new TrapezoidProfile.State();
- private TrapezoidProfile.State m_setpoint = new TrapezoidProfile.State();
- private TrapezoidProfile.Constraints m_constraints;
-
- /**
- * Allocates a ProfiledPIDController with the given constants for Kp, Ki, and
- * Kd.
- *
- * @param Kp The proportional coefficient.
- * @param Ki The integral coefficient.
- * @param Kd The derivative coefficient.
- * @param constraints Velocity and acceleration constraints for goal.
- */
- @SuppressWarnings("ParameterName")
- public ProfiledPIDController(double Kp, double Ki, double Kd,
- TrapezoidProfile.Constraints constraints) {
- this(Kp, Ki, Kd, constraints, 0.02);
- }
-
- /**
- * Allocates a ProfiledPIDController with the given constants for Kp, Ki, and
- * Kd.
- *
- * @param Kp The proportional coefficient.
- * @param Ki The integral coefficient.
- * @param Kd The derivative coefficient.
- * @param constraints Velocity and acceleration constraints for goal.
- * @param period The period between controller updates in seconds. The
- * default is 0.02 seconds.
- */
- @SuppressWarnings("ParameterName")
- public ProfiledPIDController(double Kp, double Ki, double Kd,
- TrapezoidProfile.Constraints constraints,
- double period) {
- m_controller = new PIDController(Kp, Ki, Kd, period);
- m_constraints = constraints;
- instances++;
- HAL.report(tResourceType.kResourceType_ProfiledPIDController, instances);
- }
-
- /**
- * Sets the PID Controller gain parameters.
- *
- * <p>Sets the proportional, integral, and differential coefficients.
- *
- * @param Kp Proportional coefficient
- * @param Ki Integral coefficient
- * @param Kd Differential coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setPID(double Kp, double Ki, double Kd) {
- m_controller.setPID(Kp, Ki, Kd);
- }
-
- /**
- * Sets the proportional coefficient of the PID controller gain.
- *
- * @param Kp proportional coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setP(double Kp) {
- m_controller.setP(Kp);
- }
-
- /**
- * Sets the integral coefficient of the PID controller gain.
- *
- * @param Ki integral coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setI(double Ki) {
- m_controller.setI(Ki);
- }
-
- /**
- * Sets the differential coefficient of the PID controller gain.
- *
- * @param Kd differential coefficient
- */
- @SuppressWarnings("ParameterName")
- public void setD(double Kd) {
- m_controller.setD(Kd);
- }
-
- /**
- * Gets the proportional coefficient.
- *
- * @return proportional coefficient
- */
- public double getP() {
- return m_controller.getP();
- }
-
- /**
- * Gets the integral coefficient.
- *
- * @return integral coefficient
- */
- public double getI() {
- return m_controller.getI();
- }
-
- /**
- * Gets the differential coefficient.
- *
- * @return differential coefficient
- */
- public double getD() {
- return m_controller.getD();
- }
-
- /**
- * Gets the period of this controller.
- *
- * @return The period of the controller.
- */
- public double getPeriod() {
- return m_controller.getPeriod();
- }
-
- /**
- * Sets the goal for the ProfiledPIDController.
- *
- * @param goal The desired goal state.
- */
- public void setGoal(TrapezoidProfile.State goal) {
- m_goal = goal;
- }
-
- /**
- * Sets the goal for the ProfiledPIDController.
- *
- * @param goal The desired goal position.
- */
- public void setGoal(double goal) {
- m_goal = new TrapezoidProfile.State(goal, 0);
- }
-
- /**
- * Gets the goal for the ProfiledPIDController.
- */
- public TrapezoidProfile.State getGoal() {
- return m_goal;
- }
-
- /**
- * Returns true if the error is within the tolerance of the error.
- *
- * <p>This will return false until at least one input value has been computed.
- */
- public boolean atGoal() {
- return atSetpoint() && m_goal.equals(m_setpoint);
- }
-
- /**
- * Set velocity and acceleration constraints for goal.
- *
- * @param constraints Velocity and acceleration constraints for goal.
- */
- public void setConstraints(TrapezoidProfile.Constraints constraints) {
- m_constraints = constraints;
- }
-
- /**
- * Returns the current setpoint of the ProfiledPIDController.
- *
- * @return The current setpoint.
- */
- public TrapezoidProfile.State getSetpoint() {
- return m_setpoint;
- }
-
- /**
- * Returns true if the error is within the tolerance of the error.
- *
- * <p>This will return false until at least one input value has been computed.
- */
- public boolean atSetpoint() {
- return m_controller.atSetpoint();
- }
-
- /**
- * Enables continuous input.
- *
- * <p>Rather then using the max and min input range as constraints, it considers
- * them to be the same point and automatically calculates the shortest route
- * to the setpoint.
- *
- * @param minimumInput The minimum value expected from the input.
- * @param maximumInput The maximum value expected from the input.
- */
- public void enableContinuousInput(double minimumInput, double maximumInput) {
- m_controller.enableContinuousInput(minimumInput, maximumInput);
- m_minimumInput = minimumInput;
- m_maximumInput = maximumInput;
- }
-
- /**
- * Disables continuous input.
- */
- public void disableContinuousInput() {
- m_controller.disableContinuousInput();
- }
-
- /**
- * Sets the minimum and maximum values for the integrator.
- *
- * <p>When the cap is reached, the integrator value is added to the controller
- * output rather than the integrator value times the integral gain.
- *
- * @param minimumIntegral The minimum value of the integrator.
- * @param maximumIntegral The maximum value of the integrator.
- */
- public void setIntegratorRange(double minimumIntegral, double maximumIntegral) {
- m_controller.setIntegratorRange(minimumIntegral, maximumIntegral);
- }
-
- /**
- * Sets the error which is considered tolerable for use with atSetpoint().
- *
- * @param positionTolerance Position error which is tolerable.
- */
- public void setTolerance(double positionTolerance) {
- setTolerance(positionTolerance, Double.POSITIVE_INFINITY);
- }
-
- /**
- * Sets the error which is considered tolerable for use with atSetpoint().
- *
- * @param positionTolerance Position error which is tolerable.
- * @param velocityTolerance Velocity error which is tolerable.
- */
- public void setTolerance(double positionTolerance, double velocityTolerance) {
- m_controller.setTolerance(positionTolerance, velocityTolerance);
- }
-
- /**
- * Returns the difference between the setpoint and the measurement.
- *
- * @return The error.
- */
- public double getPositionError() {
- return m_controller.getPositionError();
- }
-
- /**
- * Returns the change in error per second.
- */
- public double getVelocityError() {
- return m_controller.getVelocityError();
- }
-
- /**
- * Returns the next output of the PID controller.
- *
- * @param measurement The current measurement of the process variable.
- */
- public double calculate(double measurement) {
- if (m_controller.isContinuousInputEnabled()) {
- // Get error which is smallest distance between goal and measurement
- double goalMinDistance = ControllerUtil.getModulusError(m_goal.position, measurement,
- m_minimumInput, m_maximumInput);
- double setpointMinDistance = ControllerUtil.getModulusError(m_setpoint.position, measurement,
- m_minimumInput, m_maximumInput);
-
- // Recompute the profile goal with the smallest error, thus giving the shortest path. The goal
- // may be outside the input range after this operation, but that's OK because the controller
- // will still go there and report an error of zero. In other words, the setpoint only needs to
- // be offset from the measurement by the input range modulus; they don't need to be equal.
- m_goal.position = goalMinDistance + measurement;
- m_setpoint.position = setpointMinDistance + measurement;
- }
-
- var profile = new TrapezoidProfile(m_constraints, m_goal, m_setpoint);
- m_setpoint = profile.calculate(getPeriod());
- return m_controller.calculate(measurement, m_setpoint.position);
- }
-
- /**
- * Returns the next output of the PID controller.
- *
- * @param measurement The current measurement of the process variable.
- * @param goal The new goal of the controller.
- */
- public double calculate(double measurement, TrapezoidProfile.State goal) {
- setGoal(goal);
- return calculate(measurement);
- }
-
- /**
- * Returns the next output of the PIDController.
- *
- * @param measurement The current measurement of the process variable.
- * @param goal The new goal of the controller.
- */
- public double calculate(double measurement, double goal) {
- setGoal(goal);
- return calculate(measurement);
- }
-
- /**
- * Returns the next output of the PID controller.
- *
- * @param measurement The current measurement of the process variable.
- * @param goal The new goal of the controller.
- * @param constraints Velocity and acceleration constraints for goal.
- */
- public double calculate(double measurement, TrapezoidProfile.State goal,
- TrapezoidProfile.Constraints constraints) {
- setConstraints(constraints);
- return calculate(measurement, goal);
- }
-
- /**
- * Reset the previous error and the integral term.
- *
- * @param measurement The current measured State of the system.
- */
- public void reset(TrapezoidProfile.State measurement) {
- m_controller.reset();
- m_setpoint = measurement;
- }
-
- /**
- * Reset the previous error and the integral term.
- *
- * @param measuredPosition The current measured position of the system.
- * @param measuredVelocity The current measured velocity of the system.
- */
- public void reset(double measuredPosition, double measuredVelocity) {
- reset(new TrapezoidProfile.State(measuredPosition, measuredVelocity));
- }
-
- /**
- * Reset the previous error and the integral term.
- *
- * @param measuredPosition The current measured position of the system. The velocity is
- * assumed to be zero.
- */
- public void reset(double measuredPosition) {
- reset(measuredPosition, 0.0);
- }
-
- @Override
- public void initSendable(SendableBuilder builder) {
- builder.setSmartDashboardType("ProfiledPIDController");
- builder.addDoubleProperty("p", this::getP, this::setP);
- builder.addDoubleProperty("i", this::getI, this::setI);
- builder.addDoubleProperty("d", this::getD, this::setD);
- builder.addDoubleProperty("goal", () -> getGoal().position, this::setGoal);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/RamseteController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/RamseteController.java
deleted file mode 100644
index b597352..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/controller/RamseteController.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import edu.wpi.first.wpilibj.geometry.Pose2d;
-import edu.wpi.first.wpilibj.kinematics.ChassisSpeeds;
-import edu.wpi.first.wpilibj.trajectory.Trajectory;
-
-/**
- * Ramsete is a nonlinear time-varying feedback controller for unicycle models
- * that drives the model to a desired pose along a two-dimensional trajectory.
- * Why would we need a nonlinear control law in addition to the linear ones we
- * have used so far like PID? If we use the original approach with PID
- * controllers for left and right position and velocity states, the controllers
- * only deal with the local pose. If the robot deviates from the path, there is
- * no way for the controllers to correct and the robot may not reach the desired
- * global pose. This is due to multiple endpoints existing for the robot which
- * have the same encoder path arc lengths.
- *
- * <p>Instead of using wheel path arc lengths (which are in the robot's local
- * coordinate frame), nonlinear controllers like pure pursuit and Ramsete use
- * global pose. The controller uses this extra information to guide a linear
- * reference tracker like the PID controllers back in by adjusting the
- * references of the PID controllers.
- *
- * <p>The paper "Control of Wheeled Mobile Robots: An Experimental Overview"
- * describes a nonlinear controller for a wheeled vehicle with unicycle-like
- * kinematics; a global pose consisting of x, y, and theta; and a desired pose
- * consisting of x_d, y_d, and theta_d. We call it Ramsete because that's the
- * acronym for the title of the book it came from in Italian ("Robotica
- * Articolata e Mobile per i SErvizi e le TEcnologie").
- *
- * <p>See
- * <a href="https://file.tavsys.net/control/controls-engineering-in-frc.pdf">
- * Controls Engineering in the FIRST Robotics Competition</a> section on Ramsete
- * unicycle controller for a derivation and analysis.
- */
-public class RamseteController {
- @SuppressWarnings("MemberName")
- private final double m_b;
- @SuppressWarnings("MemberName")
- private final double m_zeta;
-
- private Pose2d m_poseError = new Pose2d();
- private Pose2d m_poseTolerance = new Pose2d();
- private boolean m_enabled = true;
-
- /**
- * Construct a Ramsete unicycle controller.
- *
- * @param b Tuning parameter (b > 0) for which larger values make convergence more
- * aggressive like a proportional term.
- * @param zeta Tuning parameter (0 < zeta < 1) for which larger values provide more damping
- * in response.
- */
- @SuppressWarnings("ParameterName")
- public RamseteController(double b, double zeta) {
- m_b = b;
- m_zeta = zeta;
- }
-
- /**
- * Construct a Ramsete unicycle controller. The default arguments for
- * b and zeta of 2.0 and 0.7 have been well-tested to produce desirable
- * results.
- */
- public RamseteController() {
- this(2.0, 0.7);
- }
-
- /**
- * Returns true if the pose error is within tolerance of the reference.
- */
- public boolean atReference() {
- final var eTranslate = m_poseError.getTranslation();
- final var eRotate = m_poseError.getRotation();
- final var tolTranslate = m_poseTolerance.getTranslation();
- final var tolRotate = m_poseTolerance.getRotation();
- return Math.abs(eTranslate.getX()) < tolTranslate.getX()
- && Math.abs(eTranslate.getY()) < tolTranslate.getY()
- && Math.abs(eRotate.getRadians()) < tolRotate.getRadians();
- }
-
- /**
- * Sets the pose error which is considered tolerable for use with
- * atReference().
- *
- * @param poseTolerance Pose error which is tolerable.
- */
- public void setTolerance(Pose2d poseTolerance) {
- m_poseTolerance = poseTolerance;
- }
-
- /**
- * Returns the next output of the Ramsete controller.
- *
- * <p>The reference pose, linear velocity, and angular velocity should come
- * from a drivetrain trajectory.
- *
- * @param currentPose The current pose.
- * @param poseRef The desired pose.
- * @param linearVelocityRefMeters The desired linear velocity in meters per second.
- * @param angularVelocityRefRadiansPerSecond The desired angular velocity in radians per second.
- */
- @SuppressWarnings("LocalVariableName")
- public ChassisSpeeds calculate(Pose2d currentPose,
- Pose2d poseRef,
- double linearVelocityRefMeters,
- double angularVelocityRefRadiansPerSecond) {
- if (!m_enabled) {
- return new ChassisSpeeds(linearVelocityRefMeters, 0.0, angularVelocityRefRadiansPerSecond);
- }
-
- m_poseError = poseRef.relativeTo(currentPose);
-
- // Aliases for equation readability
- final double eX = m_poseError.getX();
- final double eY = m_poseError.getY();
- final double eTheta = m_poseError.getRotation().getRadians();
- final double vRef = linearVelocityRefMeters;
- final double omegaRef = angularVelocityRefRadiansPerSecond;
-
- double k = 2.0 * m_zeta * Math.sqrt(Math.pow(omegaRef, 2) + m_b * Math.pow(vRef, 2));
-
- return new ChassisSpeeds(vRef * m_poseError.getRotation().getCos() + k * eX,
- 0.0,
- omegaRef + k * eTheta + m_b * vRef * sinc(eTheta) * eY);
- }
-
- /**
- * Returns the next output of the Ramsete controller.
- *
- * <p>The reference pose, linear velocity, and angular velocity should come
- * from a drivetrain trajectory.
- *
- * @param currentPose The current pose.
- * @param desiredState The desired pose, linear velocity, and angular velocity
- * from a trajectory.
- */
- @SuppressWarnings("LocalVariableName")
- public ChassisSpeeds calculate(Pose2d currentPose, Trajectory.State desiredState) {
- return calculate(currentPose, desiredState.poseMeters, desiredState.velocityMetersPerSecond,
- desiredState.velocityMetersPerSecond * desiredState.curvatureRadPerMeter);
- }
-
- /**
- * Enables and disables the controller for troubleshooting purposes.
- *
- * @param enabled If the controller is enabled or not.
- */
- public void setEnabled(boolean enabled) {
- m_enabled = enabled;
- }
-
- /**
- * Returns sin(x) / x.
- *
- * @param x Value of which to take sinc(x).
- */
- @SuppressWarnings("ParameterName")
- private static double sinc(double x) {
- if (Math.abs(x) < 1e-9) {
- return 1.0 - 1.0 / 6.0 * x * x;
- } else {
- return Math.sin(x) / x;
- }
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java
index 88a6ff9..57fb365 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java
@@ -1,60 +1,58 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.drive;
-import java.util.StringJoiner;
+import static java.util.Objects.requireNonNull;
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.math.MathUtil;
+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.SpeedController;
-import edu.wpi.first.wpilibj.SpeedControllerGroup;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-import edu.wpi.first.wpiutil.math.MathUtil;
/**
* A class for driving differential drive/skid-steer drive platforms such as the Kit of Parts drive
* base, "tank drive", or West Coast Drive.
*
* <p>These drive bases typically have drop-center / skid-steer with two or more wheels per side
- * (e.g., 6WD or 8WD). This class takes a SpeedController per side. For four and
- * six motor drivetrains, construct and pass in {@link edu.wpi.first.wpilibj.SpeedControllerGroup}
- * instances as follows.
+ * (e.g., 6WD or 8WD). This class takes a MotorController per side. For four and six motor
+ * drivetrains, construct and pass in {@link
+ * edu.wpi.first.wpilibj.motorcontrol.MotorControllerGroup} instances as follows.
*
* <p>Four motor drivetrain:
+ *
* <pre><code>
* public class Robot {
- * SpeedController m_frontLeft = new PWMVictorSPX(1);
- * SpeedController m_rearLeft = new PWMVictorSPX(2);
- * SpeedControllerGroup m_left = new SpeedControllerGroup(m_frontLeft, m_rearLeft);
+ * MotorController m_frontLeft = new PWMVictorSPX(1);
+ * MotorController m_rearLeft = new PWMVictorSPX(2);
+ * MotorControllerGroup m_left = new MotorControllerGroup(m_frontLeft, m_rearLeft);
*
- * SpeedController m_frontRight = new PWMVictorSPX(3);
- * SpeedController m_rearRight = new PWMVictorSPX(4);
- * SpeedControllerGroup m_right = new SpeedControllerGroup(m_frontRight, m_rearRight);
+ * MotorController m_frontRight = new PWMVictorSPX(3);
+ * MotorController m_rearRight = new PWMVictorSPX(4);
+ * MotorControllerGroup m_right = new MotorControllerGroup(m_frontRight, m_rearRight);
*
* DifferentialDrive m_drive = new DifferentialDrive(m_left, m_right);
* }
* </code></pre>
*
* <p>Six motor drivetrain:
+ *
* <pre><code>
* public class Robot {
- * SpeedController m_frontLeft = new PWMVictorSPX(1);
- * SpeedController m_midLeft = new PWMVictorSPX(2);
- * SpeedController m_rearLeft = new PWMVictorSPX(3);
- * SpeedControllerGroup m_left = new SpeedControllerGroup(m_frontLeft, m_midLeft, m_rearLeft);
+ * MotorController m_frontLeft = new PWMVictorSPX(1);
+ * MotorController m_midLeft = new PWMVictorSPX(2);
+ * MotorController m_rearLeft = new PWMVictorSPX(3);
+ * MotorControllerGroup m_left = new MotorControllerGroup(m_frontLeft, m_midLeft, m_rearLeft);
*
- * SpeedController m_frontRight = new PWMVictorSPX(4);
- * SpeedController m_midRight = new PWMVictorSPX(5);
- * SpeedController m_rearRight = new PWMVictorSPX(6);
- * SpeedControllerGroup m_right = new SpeedControllerGroup(m_frontRight, m_midRight, m_rearRight);
+ * MotorController m_frontRight = new PWMVictorSPX(4);
+ * MotorController m_midRight = new PWMVictorSPX(5);
+ * MotorController m_rearRight = new PWMVictorSPX(6);
+ * MotorControllerGroup m_right = new MotorControllerGroup(m_frontRight, m_midRight, m_rearRight);
*
* DifferentialDrive m_drive = new DifferentialDrive(m_left, m_right);
* }
@@ -63,6 +61,7 @@
* <p>A differential drive robot has left and right wheels separated by an arbitrary width.
*
* <p>Drive base diagram:
+ *
* <pre>
* |_______|
* | | | |
@@ -83,42 +82,52 @@
* positive.
*
* <p>Inputs smaller then {@value edu.wpi.first.wpilibj.drive.RobotDriveBase#kDefaultDeadband} will
- * be set to 0, and larger values will be scaled so that the full range is still used. This
- * deadband value can be changed with {@link #setDeadband}.
- *
- * <p>RobotDrive porting guide:
- * <br>{@link #tankDrive(double, double)} is equivalent to
- * {@link edu.wpi.first.wpilibj.RobotDrive#tankDrive(double, double)} if a deadband of 0 is used.
- * <br>{@link #arcadeDrive(double, double)} is equivalent to
- * {@link edu.wpi.first.wpilibj.RobotDrive#arcadeDrive(double, double)} if a deadband of 0 is used
- * and the the rotation input is inverted eg arcadeDrive(y, -rotation)
- * <br>{@link #curvatureDrive(double, double, boolean)} is similar in concept to
- * {@link edu.wpi.first.wpilibj.RobotDrive#drive(double, double)} with the addition of a quick turn
- * mode. However, it is not designed to give exactly the same response.
+ * be set to 0, and larger values will be scaled so that the full range is still used. This deadband
+ * value can be changed with {@link #setDeadband}.
*/
+@SuppressWarnings("removal")
public class DifferentialDrive extends RobotDriveBase implements Sendable, AutoCloseable {
- public static final double kDefaultQuickStopThreshold = 0.2;
- public static final double kDefaultQuickStopAlpha = 0.1;
-
private static int instances;
private final SpeedController m_leftMotor;
private final SpeedController m_rightMotor;
- private double m_quickStopThreshold = kDefaultQuickStopThreshold;
- private double m_quickStopAlpha = kDefaultQuickStopAlpha;
- private double m_quickStopAccumulator;
- private double m_rightSideInvertMultiplier = -1.0;
private boolean m_reported;
+ @SuppressWarnings("MemberName")
+ public static class WheelSpeeds {
+ public double left;
+ public double right;
+
+ /** Constructs a WheelSpeeds with zeroes for left and right speeds. */
+ public WheelSpeeds() {}
+
+ /**
+ * Constructs a WheelSpeeds.
+ *
+ * @param left The left speed.
+ * @param right The right speed.
+ */
+ public WheelSpeeds(double left, double right) {
+ this.left = left;
+ this.right = right;
+ }
+ }
+
/**
* Construct a DifferentialDrive.
*
- * <p>To pass multiple motors per side, use a {@link SpeedControllerGroup}. If a motor needs to be
- * inverted, do so before passing it in.
+ * <p>To pass multiple motors per side, use a {@link
+ * edu.wpi.first.wpilibj.motorcontrol.MotorControllerGroup}. If a motor needs to be inverted, do
+ * so before passing it in.
+ *
+ * @param leftMotor Left motor.
+ * @param rightMotor Right motor.
*/
public DifferentialDrive(SpeedController leftMotor, SpeedController rightMotor) {
- verify(leftMotor, rightMotor);
+ requireNonNull(leftMotor, "Left motor cannot be null");
+ requireNonNull(rightMotor, "Right motor cannot be null");
+
m_leftMotor = leftMotor;
m_rightMotor = rightMotor;
SendableRegistry.addChild(this, m_leftMotor);
@@ -133,35 +142,12 @@
}
/**
- * Verifies that all motors are nonnull, throwing a NullPointerException if any of them are.
- * The exception's error message will specify all null motors, e.g. {@code
- * NullPointerException("leftMotor, rightMotor")}, to give as much information as possible to
- * the programmer.
+ * Arcade drive method for differential drive platform. The calculated values will be squared to
+ * decrease sensitivity at low speeds.
*
- * @throws NullPointerException if any of the given motors are null
- */
- @SuppressWarnings("PMD.AvoidThrowingNullPointerException")
- private void verify(SpeedController leftMotor, SpeedController rightMotor) {
- if (leftMotor != null && rightMotor != null) {
- return;
- }
- StringJoiner joiner = new StringJoiner(", ");
- if (leftMotor == null) {
- joiner.add("leftMotor");
- }
- if (rightMotor == null) {
- joiner.add("rightMotor");
- }
- throw new NullPointerException(joiner.toString());
- }
-
- /**
- * Arcade drive method for differential drive platform.
- * The calculated values will be squared to decrease sensitivity at low speeds.
- *
- * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
+ * positive.
*/
@SuppressWarnings("ParameterName")
public void arcadeDrive(double xSpeed, double zRotation) {
@@ -171,60 +157,26 @@
/**
* Arcade drive method for differential drive platform.
*
- * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
- * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+ * positive.
* @param squareInputs If set, decreases the input sensitivity at low speeds.
*/
@SuppressWarnings("ParameterName")
public void arcadeDrive(double xSpeed, double zRotation, boolean squareInputs) {
if (!m_reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive,
- tInstances.kRobotDrive2_DifferentialArcade, 2);
+ HAL.report(
+ tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive2_DifferentialArcade, 2);
m_reported = true;
}
- xSpeed = MathUtil.clamp(xSpeed, -1.0, 1.0);
- xSpeed = applyDeadband(xSpeed, m_deadband);
+ xSpeed = MathUtil.applyDeadband(xSpeed, m_deadband);
+ zRotation = MathUtil.applyDeadband(zRotation, m_deadband);
- zRotation = MathUtil.clamp(zRotation, -1.0, 1.0);
- zRotation = applyDeadband(zRotation, m_deadband);
+ var speeds = arcadeDriveIK(xSpeed, zRotation, squareInputs);
- // Square the inputs (while preserving the sign) to increase fine control
- // while permitting full power.
- if (squareInputs) {
- xSpeed = Math.copySign(xSpeed * xSpeed, xSpeed);
- zRotation = Math.copySign(zRotation * zRotation, zRotation);
- }
-
- double leftMotorOutput;
- double rightMotorOutput;
-
- double maxInput = Math.copySign(Math.max(Math.abs(xSpeed), Math.abs(zRotation)), xSpeed);
-
- if (xSpeed >= 0.0) {
- // First quadrant, else second quadrant
- if (zRotation >= 0.0) {
- leftMotorOutput = maxInput;
- rightMotorOutput = xSpeed - zRotation;
- } else {
- leftMotorOutput = xSpeed + zRotation;
- rightMotorOutput = maxInput;
- }
- } else {
- // Third quadrant, else fourth quadrant
- if (zRotation >= 0.0) {
- leftMotorOutput = xSpeed + zRotation;
- rightMotorOutput = maxInput;
- } else {
- leftMotorOutput = maxInput;
- rightMotorOutput = xSpeed - zRotation;
- }
- }
-
- m_leftMotor.set(MathUtil.clamp(leftMotorOutput, -1.0, 1.0) * m_maxOutput);
- double maxOutput = m_maxOutput * m_rightSideInvertMultiplier;
- m_rightMotor.set(MathUtil.clamp(rightMotorOutput, -1.0, 1.0) * maxOutput);
+ m_leftMotor.set(speeds.left * m_maxOutput);
+ m_rightMotor.set(speeds.right * m_maxOutput);
feed();
}
@@ -233,94 +185,40 @@
* Curvature drive method for differential drive platform.
*
* <p>The rotation argument controls the curvature of the robot's path rather than its rate of
- * heading change. This makes the robot more controllable at high speeds. Also handles the
- * robot's quick turn functionality - "quick turn" overrides constant-curvature turning for
- * turn-in-place maneuvers.
+ * heading change. This makes the robot more controllable at high speeds.
*
- * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
- * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
- * @param isQuickTurn If set, overrides constant-curvature turning for
- * turn-in-place maneuvers.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+ * positive.
+ * @param allowTurnInPlace If set, overrides constant-curvature turning for turn-in-place
+ * maneuvers.
*/
- @SuppressWarnings({"ParameterName", "PMD.CyclomaticComplexity"})
- public void curvatureDrive(double xSpeed, double zRotation, boolean isQuickTurn) {
+ @SuppressWarnings("ParameterName")
+ public void curvatureDrive(double xSpeed, double zRotation, boolean allowTurnInPlace) {
if (!m_reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive,
- tInstances.kRobotDrive2_DifferentialCurvature, 2);
+ HAL.report(
+ tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive2_DifferentialCurvature, 2);
m_reported = true;
}
- xSpeed = MathUtil.clamp(xSpeed, -1.0, 1.0);
- xSpeed = applyDeadband(xSpeed, m_deadband);
+ xSpeed = MathUtil.applyDeadband(xSpeed, m_deadband);
+ zRotation = MathUtil.applyDeadband(zRotation, m_deadband);
- zRotation = MathUtil.clamp(zRotation, -1.0, 1.0);
- zRotation = applyDeadband(zRotation, m_deadband);
+ var speeds = curvatureDriveIK(xSpeed, zRotation, allowTurnInPlace);
- double angularPower;
- boolean overPower;
-
- if (isQuickTurn) {
- if (Math.abs(xSpeed) < m_quickStopThreshold) {
- m_quickStopAccumulator = (1 - m_quickStopAlpha) * m_quickStopAccumulator
- + m_quickStopAlpha * MathUtil.clamp(zRotation, -1.0, 1.0) * 2;
- }
- overPower = true;
- angularPower = zRotation;
- } else {
- overPower = false;
- angularPower = Math.abs(xSpeed) * zRotation - m_quickStopAccumulator;
-
- if (m_quickStopAccumulator > 1) {
- m_quickStopAccumulator -= 1;
- } else if (m_quickStopAccumulator < -1) {
- m_quickStopAccumulator += 1;
- } else {
- m_quickStopAccumulator = 0.0;
- }
- }
-
- double leftMotorOutput = xSpeed + angularPower;
- double rightMotorOutput = xSpeed - angularPower;
-
- // If rotation is overpowered, reduce both outputs to within acceptable range
- if (overPower) {
- if (leftMotorOutput > 1.0) {
- rightMotorOutput -= leftMotorOutput - 1.0;
- leftMotorOutput = 1.0;
- } else if (rightMotorOutput > 1.0) {
- leftMotorOutput -= rightMotorOutput - 1.0;
- rightMotorOutput = 1.0;
- } else if (leftMotorOutput < -1.0) {
- rightMotorOutput -= leftMotorOutput + 1.0;
- leftMotorOutput = -1.0;
- } else if (rightMotorOutput < -1.0) {
- leftMotorOutput -= rightMotorOutput + 1.0;
- rightMotorOutput = -1.0;
- }
- }
-
- // Normalize the wheel speeds
- double maxMagnitude = Math.max(Math.abs(leftMotorOutput), Math.abs(rightMotorOutput));
- if (maxMagnitude > 1.0) {
- leftMotorOutput /= maxMagnitude;
- rightMotorOutput /= maxMagnitude;
- }
-
- m_leftMotor.set(leftMotorOutput * m_maxOutput);
- m_rightMotor.set(rightMotorOutput * m_maxOutput * m_rightSideInvertMultiplier);
+ m_leftMotor.set(speeds.left * m_maxOutput);
+ m_rightMotor.set(speeds.right * m_maxOutput);
feed();
}
/**
- * Tank drive method for differential drive platform.
- * The calculated values will be squared to decrease sensitivity at low speeds.
+ * Tank drive method for differential drive platform. The calculated values will be squared to
+ * decrease sensitivity at low speeds.
*
- * @param leftSpeed The robot's left side speed along the X axis [-1.0..1.0]. Forward is
- * positive.
+ * @param leftSpeed The robot's left side speed along the X axis [-1.0..1.0]. Forward is positive.
* @param rightSpeed The robot's right side speed along the X axis [-1.0..1.0]. Forward is
- * positive.
+ * positive.
*/
public void tankDrive(double leftSpeed, double rightSpeed) {
tankDrive(leftSpeed, rightSpeed, true);
@@ -329,24 +227,137 @@
/**
* Tank drive method for differential drive platform.
*
- * @param leftSpeed The robot left side's speed along the X axis [-1.0..1.0]. Forward is
- * positive.
- * @param rightSpeed The robot right side's speed along the X axis [-1.0..1.0]. Forward is
- * positive.
+ * @param leftSpeed The robot left side's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param rightSpeed The robot right side's speed along the X axis [-1.0..1.0]. Forward is
+ * positive.
* @param squareInputs If set, decreases the input sensitivity at low speeds.
*/
public void tankDrive(double leftSpeed, double rightSpeed, boolean squareInputs) {
if (!m_reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive,
- tInstances.kRobotDrive2_DifferentialTank, 2);
+ HAL.report(
+ tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive2_DifferentialTank, 2);
m_reported = true;
}
- leftSpeed = MathUtil.clamp(leftSpeed, -1.0, 1.0);
- leftSpeed = applyDeadband(leftSpeed, m_deadband);
+ leftSpeed = MathUtil.applyDeadband(leftSpeed, m_deadband);
+ rightSpeed = MathUtil.applyDeadband(rightSpeed, m_deadband);
+ var speeds = tankDriveIK(leftSpeed, rightSpeed, squareInputs);
+
+ m_leftMotor.set(speeds.left * m_maxOutput);
+ m_rightMotor.set(speeds.right * m_maxOutput);
+
+ feed();
+ }
+
+ /**
+ * Arcade drive inverse kinematics for differential drive platform.
+ *
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+ * positive.
+ * @param squareInputs If set, decreases the input sensitivity at low speeds.
+ * @return Wheel speeds.
+ */
+ @SuppressWarnings("ParameterName")
+ public static WheelSpeeds arcadeDriveIK(double xSpeed, double zRotation, boolean squareInputs) {
+ xSpeed = MathUtil.clamp(xSpeed, -1.0, 1.0);
+ zRotation = MathUtil.clamp(zRotation, -1.0, 1.0);
+
+ // Square the inputs (while preserving the sign) to increase fine control
+ // while permitting full power.
+ if (squareInputs) {
+ xSpeed = Math.copySign(xSpeed * xSpeed, xSpeed);
+ zRotation = Math.copySign(zRotation * zRotation, zRotation);
+ }
+
+ double leftSpeed;
+ double rightSpeed;
+
+ double maxInput = Math.copySign(Math.max(Math.abs(xSpeed), Math.abs(zRotation)), xSpeed);
+
+ if (xSpeed >= 0.0) {
+ // First quadrant, else second quadrant
+ if (zRotation >= 0.0) {
+ leftSpeed = maxInput;
+ rightSpeed = xSpeed - zRotation;
+ } else {
+ leftSpeed = xSpeed + zRotation;
+ rightSpeed = maxInput;
+ }
+ } else {
+ // Third quadrant, else fourth quadrant
+ if (zRotation >= 0.0) {
+ leftSpeed = xSpeed + zRotation;
+ rightSpeed = maxInput;
+ } else {
+ leftSpeed = maxInput;
+ rightSpeed = xSpeed - zRotation;
+ }
+ }
+
+ // Normalize the wheel speeds
+ double maxMagnitude = Math.max(Math.abs(leftSpeed), Math.abs(rightSpeed));
+ if (maxMagnitude > 1.0) {
+ leftSpeed /= maxMagnitude;
+ rightSpeed /= maxMagnitude;
+ }
+
+ return new WheelSpeeds(leftSpeed, rightSpeed);
+ }
+
+ /**
+ * Curvature drive inverse kinematics for differential drive platform.
+ *
+ * <p>The rotation argument controls the curvature of the robot's path rather than its rate of
+ * heading change. This makes the robot more controllable at high speeds.
+ *
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+ * positive.
+ * @param allowTurnInPlace If set, overrides constant-curvature turning for turn-in-place
+ * maneuvers.
+ * @return Wheel speeds.
+ */
+ @SuppressWarnings("ParameterName")
+ public static WheelSpeeds curvatureDriveIK(
+ double xSpeed, double zRotation, boolean allowTurnInPlace) {
+ xSpeed = MathUtil.clamp(xSpeed, -1.0, 1.0);
+ zRotation = MathUtil.clamp(zRotation, -1.0, 1.0);
+
+ double leftSpeed = 0.0;
+ double rightSpeed = 0.0;
+
+ if (allowTurnInPlace) {
+ leftSpeed = xSpeed + zRotation;
+ rightSpeed = xSpeed - zRotation;
+ } else {
+ leftSpeed = xSpeed + Math.abs(xSpeed) * zRotation;
+ rightSpeed = xSpeed - Math.abs(xSpeed) * zRotation;
+ }
+
+ // Normalize wheel speeds
+ double maxMagnitude = Math.max(Math.abs(leftSpeed), Math.abs(rightSpeed));
+ if (maxMagnitude > 1.0) {
+ leftSpeed /= maxMagnitude;
+ rightSpeed /= maxMagnitude;
+ }
+
+ return new WheelSpeeds(leftSpeed, rightSpeed);
+ }
+
+ /**
+ * Tank drive inverse kinematics for differential drive platform.
+ *
+ * @param leftSpeed The robot left side's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param rightSpeed The robot right side's speed along the X axis [-1.0..1.0]. Forward is
+ * positive.
+ * @param squareInputs If set, decreases the input sensitivity at low speeds.
+ * @return Wheel speeds.
+ */
+ public static WheelSpeeds tankDriveIK(double leftSpeed, double rightSpeed, boolean squareInputs) {
+ leftSpeed = MathUtil.clamp(leftSpeed, -1.0, 1.0);
rightSpeed = MathUtil.clamp(rightSpeed, -1.0, 1.0);
- rightSpeed = applyDeadband(rightSpeed, m_deadband);
// Square the inputs (while preserving the sign) to increase fine control
// while permitting full power.
@@ -355,59 +366,7 @@
rightSpeed = Math.copySign(rightSpeed * rightSpeed, rightSpeed);
}
- m_leftMotor.set(leftSpeed * m_maxOutput);
- m_rightMotor.set(rightSpeed * m_maxOutput * m_rightSideInvertMultiplier);
-
- feed();
- }
-
- /**
- * Sets the QuickStop speed threshold in curvature drive.
- *
- * <p>QuickStop compensates for the robot's moment of inertia when stopping after a QuickTurn.
- *
- * <p>While QuickTurn is enabled, the QuickStop accumulator takes on the rotation rate value
- * outputted by the low-pass filter when the robot's speed along the X axis is below the
- * threshold. When QuickTurn is disabled, the accumulator's value is applied against the computed
- * angular power request to slow the robot's rotation.
- *
- * @param threshold X speed below which quick stop accumulator will receive rotation rate values
- * [0..1.0].
- */
- public void setQuickStopThreshold(double threshold) {
- m_quickStopThreshold = threshold;
- }
-
- /**
- * Sets the low-pass filter gain for QuickStop in curvature drive.
- *
- * <p>The low-pass filter filters incoming rotation rate commands to smooth out high frequency
- * changes.
- *
- * @param alpha Low-pass filter gain [0.0..2.0]. Smaller values result in slower output changes.
- * Values between 1.0 and 2.0 result in output oscillation. Values below 0.0 and
- * above 2.0 are unstable.
- */
- public void setQuickStopAlpha(double alpha) {
- m_quickStopAlpha = alpha;
- }
-
- /**
- * Gets if the power sent to the right side of the drivetrain is multiplied by -1.
- *
- * @return true if the right side is inverted
- */
- public boolean isRightSideInverted() {
- return m_rightSideInvertMultiplier == -1.0;
- }
-
- /**
- * Sets if the power sent to the right side of the drivetrain should be multiplied by -1.
- *
- * @param rightSideInverted true if right side power should be multiplied by -1
- */
- public void setRightSideInverted(boolean rightSideInverted) {
- m_rightSideInvertMultiplier = rightSideInverted ? -1.0 : 1.0;
+ return new WheelSpeeds(leftSpeed, rightSpeed);
}
@Override
@@ -429,8 +388,6 @@
builder.setSafeState(this::stopMotor);
builder.addDoubleProperty("Left Motor Speed", m_leftMotor::get, m_leftMotor::set);
builder.addDoubleProperty(
- "Right Motor Speed",
- () -> m_rightMotor.get() * m_rightSideInvertMultiplier,
- x -> m_rightMotor.set(x * m_rightSideInvertMultiplier));
+ "Right Motor Speed", () -> m_rightMotor.get(), x -> m_rightMotor.set(x));
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java
index 45da78a..3c49989 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java
@@ -1,22 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.drive;
-import java.util.StringJoiner;
+import static java.util.Objects.requireNonNull;
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.math.MathUtil;
+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.SpeedController;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-import edu.wpi.first.wpiutil.math.MathUtil;
/**
* A class for driving Killough drive platforms.
@@ -24,6 +21,7 @@
* <p>Killough drives are triangular with one omni wheel on each corner.
*
* <p>Drive base diagram:
+ *
* <pre>
* /_____\
* / \ / \
@@ -42,6 +40,7 @@
* points down. Rotations follow the right-hand rule, so clockwise rotation around the Z axis is
* positive.
*/
+@SuppressWarnings("removal")
public class KilloughDrive extends RobotDriveBase implements Sendable, AutoCloseable {
public static final double kDefaultLeftMotorAngle = 60.0;
public static final double kDefaultRightMotorAngle = 120.0;
@@ -59,6 +58,29 @@
private boolean m_reported;
+ @SuppressWarnings("MemberName")
+ public static class WheelSpeeds {
+ public double left;
+ public double right;
+ public double back;
+
+ /** Constructs a WheelSpeeds with zeroes for left, right, and back speeds. */
+ public WheelSpeeds() {}
+
+ /**
+ * Constructs a WheelSpeeds.
+ *
+ * @param left The left speed.
+ * @param right The right speed.
+ * @param back The back speed.
+ */
+ public WheelSpeeds(double left, double right, double back) {
+ this.left = left;
+ this.right = right;
+ this.back = back;
+ }
+ }
+
/**
* Construct a Killough drive with the given motors and default motor angles.
*
@@ -67,13 +89,18 @@
*
* <p>If a motor needs to be inverted, do so before passing it in.
*
- * @param leftMotor The motor on the left corner.
+ * @param leftMotor The motor on the left corner.
* @param rightMotor The motor on the right corner.
- * @param backMotor The motor on the back corner.
+ * @param backMotor The motor on the back corner.
*/
- public KilloughDrive(SpeedController leftMotor, SpeedController rightMotor,
- SpeedController backMotor) {
- this(leftMotor, rightMotor, backMotor, kDefaultLeftMotorAngle, kDefaultRightMotorAngle,
+ public KilloughDrive(
+ SpeedController leftMotor, SpeedController rightMotor, SpeedController backMotor) {
+ this(
+ leftMotor,
+ rightMotor,
+ backMotor,
+ kDefaultLeftMotorAngle,
+ kDefaultRightMotorAngle,
kDefaultBackMotorAngle);
}
@@ -82,26 +109,39 @@
*
* <p>Angles are measured in degrees clockwise from the positive X axis.
*
- * @param leftMotor The motor on the left corner.
- * @param rightMotor The motor on the right corner.
- * @param backMotor The motor on the back corner.
- * @param leftMotorAngle The angle of the left wheel's forward direction of travel.
+ * @param leftMotor The motor on the left corner.
+ * @param rightMotor The motor on the right corner.
+ * @param backMotor The motor on the back corner.
+ * @param leftMotorAngle The angle of the left wheel's forward direction of travel.
* @param rightMotorAngle The angle of the right wheel's forward direction of travel.
- * @param backMotorAngle The angle of the back wheel's forward direction of travel.
+ * @param backMotorAngle The angle of the back wheel's forward direction of travel.
*/
- public KilloughDrive(SpeedController leftMotor, SpeedController rightMotor,
- SpeedController backMotor, double leftMotorAngle, double rightMotorAngle,
- double backMotorAngle) {
- verify(leftMotor, rightMotor, backMotor);
+ public KilloughDrive(
+ SpeedController leftMotor,
+ SpeedController rightMotor,
+ SpeedController backMotor,
+ double leftMotorAngle,
+ double rightMotorAngle,
+ double backMotorAngle) {
+ requireNonNull(leftMotor, "Left motor cannot be null");
+ requireNonNull(rightMotor, "Right motor cannot be null");
+ requireNonNull(backMotor, "Back motor cannot be null");
+
m_leftMotor = leftMotor;
m_rightMotor = rightMotor;
m_backMotor = backMotor;
- m_leftVec = new Vector2d(Math.cos(leftMotorAngle * (Math.PI / 180.0)),
- Math.sin(leftMotorAngle * (Math.PI / 180.0)));
- m_rightVec = new Vector2d(Math.cos(rightMotorAngle * (Math.PI / 180.0)),
- Math.sin(rightMotorAngle * (Math.PI / 180.0)));
- m_backVec = new Vector2d(Math.cos(backMotorAngle * (Math.PI / 180.0)),
- Math.sin(backMotorAngle * (Math.PI / 180.0)));
+ m_leftVec =
+ new Vector2d(
+ Math.cos(leftMotorAngle * (Math.PI / 180.0)),
+ Math.sin(leftMotorAngle * (Math.PI / 180.0)));
+ m_rightVec =
+ new Vector2d(
+ Math.cos(rightMotorAngle * (Math.PI / 180.0)),
+ Math.sin(rightMotorAngle * (Math.PI / 180.0)));
+ m_backVec =
+ new Vector2d(
+ Math.cos(backMotorAngle * (Math.PI / 180.0)),
+ Math.sin(backMotorAngle * (Math.PI / 180.0)));
SendableRegistry.addChild(this, m_leftMotor);
SendableRegistry.addChild(this, m_rightMotor);
SendableRegistry.addChild(this, m_backMotor);
@@ -115,42 +155,15 @@
}
/**
- * Verifies that all motors are nonnull, throwing a NullPointerException if any of them are.
- * The exception's error message will specify all null motors, e.g. {@code
- * NullPointerException("leftMotor, rightMotor")}, to give as much information as possible to
- * the programmer.
- *
- * @throws NullPointerException if any of the given motors are null
- */
- @SuppressWarnings("PMD.AvoidThrowingNullPointerException")
- private void verify(SpeedController leftMotor, SpeedController rightMotor,
- SpeedController backMotor) {
- if (leftMotor != null && rightMotor != null && backMotor != null) {
- return;
- }
- StringJoiner joiner = new StringJoiner(", ");
- if (leftMotor == null) {
- joiner.add("leftMotor");
- }
- if (rightMotor == null) {
- joiner.add("rightMotor");
- }
- if (backMotor == null) {
- joiner.add("backMotor");
- }
- throw new NullPointerException(joiner.toString());
- }
-
- /**
* Drive method for Killough platform.
*
* <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
* from its angle or rotation rate.
*
- * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
- * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
+ * positive.
*/
@SuppressWarnings("ParameterName")
public void driveCartesian(double ySpeed, double xSpeed, double zRotation) {
@@ -163,27 +176,77 @@
* <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
* from its angle or rotation rate.
*
- * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
- * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
- * @param gyroAngle The current angle reading from the gyro in degrees around the Z axis. Use
- * this to implement field-oriented controls.
+ * positive.
+ * @param gyroAngle The current angle reading from the gyro in degrees around the Z axis. Use this
+ * to implement field-oriented controls.
*/
@SuppressWarnings("ParameterName")
- public void driveCartesian(double ySpeed, double xSpeed, double zRotation,
- double gyroAngle) {
+ public void driveCartesian(double ySpeed, double xSpeed, double zRotation, double gyroAngle) {
if (!m_reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive,
- tInstances.kRobotDrive2_KilloughCartesian, 3);
+ HAL.report(
+ tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive2_KilloughCartesian, 3);
m_reported = true;
}
- ySpeed = MathUtil.clamp(ySpeed, -1.0, 1.0);
- ySpeed = applyDeadband(ySpeed, m_deadband);
+ ySpeed = MathUtil.applyDeadband(ySpeed, m_deadband);
+ xSpeed = MathUtil.applyDeadband(xSpeed, m_deadband);
+ var speeds = driveCartesianIK(ySpeed, xSpeed, zRotation, gyroAngle);
+
+ m_leftMotor.set(speeds.left * m_maxOutput);
+ m_rightMotor.set(speeds.right * m_maxOutput);
+ m_backMotor.set(speeds.back * m_maxOutput);
+
+ feed();
+ }
+
+ /**
+ * Drive method for Killough platform.
+ *
+ * <p>Angles are measured counter-clockwise from straight ahead. The speed at which the robot
+ * drives (translation) is independent from its angle or rotation rate.
+ *
+ * @param magnitude The robot's speed at a given angle [-1.0..1.0]. Forward is positive.
+ * @param angle The angle around the Z axis at which the robot drives in degrees [-180..180].
+ * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+ * positive.
+ */
+ @SuppressWarnings("ParameterName")
+ public void drivePolar(double magnitude, double angle, double zRotation) {
+ if (!m_reported) {
+ HAL.report(tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive2_KilloughPolar, 3);
+ m_reported = true;
+ }
+
+ driveCartesian(
+ magnitude * Math.sin(angle * (Math.PI / 180.0)),
+ magnitude * Math.cos(angle * (Math.PI / 180.0)),
+ zRotation,
+ 0.0);
+ }
+
+ /**
+ * Cartesian inverse kinematics for Killough platform.
+ *
+ * <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
+ * from its angle or rotation rate.
+ *
+ * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+ * positive.
+ * @param gyroAngle The current angle reading from the gyro in degrees around the Z axis. Use this
+ * to implement field-oriented controls.
+ * @return Wheel speeds.
+ */
+ @SuppressWarnings("ParameterName")
+ public WheelSpeeds driveCartesianIK(
+ double ySpeed, double xSpeed, double zRotation, double gyroAngle) {
+ ySpeed = MathUtil.clamp(ySpeed, -1.0, 1.0);
xSpeed = MathUtil.clamp(xSpeed, -1.0, 1.0);
- xSpeed = applyDeadband(xSpeed, m_deadband);
// Compensate for gyro angle.
Vector2d input = new Vector2d(ySpeed, xSpeed);
@@ -196,34 +259,10 @@
normalize(wheelSpeeds);
- m_leftMotor.set(wheelSpeeds[MotorType.kLeft.value] * m_maxOutput);
- m_rightMotor.set(wheelSpeeds[MotorType.kRight.value] * m_maxOutput);
- m_backMotor.set(wheelSpeeds[MotorType.kBack.value] * m_maxOutput);
-
- feed();
- }
-
- /**
- * Drive method for Killough platform.
- *
- * <p>Angles are measured counter-clockwise from straight ahead. The speed at which the robot
- * drives (translation) is independent from its angle or rotation rate.
- *
- * @param magnitude The robot's speed at a given angle [-1.0..1.0]. Forward is positive.
- * @param angle The angle around the Z axis at which the robot drives in degrees [-180..180].
- * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
- */
- @SuppressWarnings("ParameterName")
- public void drivePolar(double magnitude, double angle, double zRotation) {
- if (!m_reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive,
- tInstances.kRobotDrive2_KilloughPolar, 3);
- m_reported = true;
- }
-
- driveCartesian(magnitude * Math.sin(angle * (Math.PI / 180.0)),
- magnitude * Math.cos(angle * (Math.PI / 180.0)), zRotation, 0.0);
+ return new WheelSpeeds(
+ wheelSpeeds[MotorType.kLeft.value],
+ wheelSpeeds[MotorType.kRight.value],
+ wheelSpeeds[MotorType.kBack.value]);
}
@Override
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java
index d709004..b672fa8 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java
@@ -1,22 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.drive;
-import java.util.StringJoiner;
+import static java.util.Objects.requireNonNull;
import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.math.MathUtil;
+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.SpeedController;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-import edu.wpi.first.wpiutil.math.MathUtil;
/**
* A class for driving Mecanum drive platforms.
@@ -27,6 +24,7 @@
* relations for a Mecanum drive robot.
*
* <p>Drive base diagram:
+ *
* <pre>
* \\_______/
* \\ | | /
@@ -47,20 +45,20 @@
* positive.
*
* <p>Inputs smaller then {@value edu.wpi.first.wpilibj.drive.RobotDriveBase#kDefaultDeadband} will
- * be set to 0, and larger values will be scaled so that the full range is still used. This
- * deadband value can be changed with {@link #setDeadband}.
+ * be set to 0, and larger values will be scaled so that the full range is still used. This deadband
+ * value can be changed with {@link #setDeadband}.
*
- * <p>RobotDrive porting guide:
- * <br>In MecanumDrive, the right side speed controllers are automatically inverted, while in
- * RobotDrive, no speed controllers are automatically inverted.
- * <br>{@link #driveCartesian(double, double, double, double)} is equivalent to
- * {@link edu.wpi.first.wpilibj.RobotDrive#mecanumDrive_Cartesian(double, double, double, double)}
- * if a deadband of 0 is used, and the ySpeed and gyroAngle values are inverted compared to
- * RobotDrive (eg driveCartesian(xSpeed, -ySpeed, zRotation, -gyroAngle).
- * <br>{@link #drivePolar(double, double, double)} is equivalent to
- * {@link edu.wpi.first.wpilibj.RobotDrive#mecanumDrive_Polar(double, double, double)} if a
- * deadband of 0 is used.
+ * <p>RobotDrive porting guide: <br>
+ * In MecanumDrive, the right side motor controllers are automatically inverted, while in
+ * RobotDrive, no motor controllers are automatically inverted. <br>
+ * {@link #driveCartesian(double, double, double, double)} is equivalent to RobotDrive's
+ * mecanumDrive_Cartesian(double, double, double, double) if a deadband of 0 is used, and the ySpeed
+ * and gyroAngle values are inverted compared to RobotDrive (eg driveCartesian(xSpeed, -ySpeed,
+ * zRotation, -gyroAngle). <br>
+ * {@link #drivePolar(double, double, double)} is equivalent to RobotDrive's
+ * mecanumDrive_Polar(double, double, double)} if a deadband of 0 is used.
*/
+@SuppressWarnings("removal")
public class MecanumDrive extends RobotDriveBase implements Sendable, AutoCloseable {
private static int instances;
@@ -69,17 +67,54 @@
private final SpeedController m_frontRightMotor;
private final SpeedController m_rearRightMotor;
- private double m_rightSideInvertMultiplier = -1.0;
private boolean m_reported;
+ @SuppressWarnings("MemberName")
+ public static class WheelSpeeds {
+ public double frontLeft;
+ public double frontRight;
+ public double rearLeft;
+ public double rearRight;
+
+ /** Constructs a WheelSpeeds with zeroes for all four speeds. */
+ public WheelSpeeds() {}
+
+ /**
+ * Constructs a WheelSpeeds.
+ *
+ * @param frontLeft The front left speed.
+ * @param frontRight The front right speed.
+ * @param rearLeft The rear left speed.
+ * @param rearRight The rear right speed.
+ */
+ public WheelSpeeds(double frontLeft, double frontRight, double rearLeft, double rearRight) {
+ this.frontLeft = frontLeft;
+ this.frontRight = frontRight;
+ this.rearLeft = rearLeft;
+ this.rearRight = rearRight;
+ }
+ }
+
/**
* Construct a MecanumDrive.
*
* <p>If a motor needs to be inverted, do so before passing it in.
+ *
+ * @param frontLeftMotor The motor on the front-left corner.
+ * @param rearLeftMotor The motor on the rear-left corner.
+ * @param frontRightMotor The motor on the front-right corner.
+ * @param rearRightMotor The motor on the rear-right corner.
*/
- public MecanumDrive(SpeedController frontLeftMotor, SpeedController rearLeftMotor,
- SpeedController frontRightMotor, SpeedController rearRightMotor) {
- verify(frontLeftMotor, rearLeftMotor, frontRightMotor, rearRightMotor);
+ public MecanumDrive(
+ SpeedController frontLeftMotor,
+ SpeedController rearLeftMotor,
+ SpeedController frontRightMotor,
+ SpeedController rearRightMotor) {
+ requireNonNull(frontLeftMotor, "Front-left motor cannot be null");
+ requireNonNull(rearLeftMotor, "Rear-left motor cannot be null");
+ requireNonNull(frontRightMotor, "Front-right motor cannot be null");
+ requireNonNull(rearRightMotor, "Rear-right motor cannot be null");
+
m_frontLeftMotor = frontLeftMotor;
m_rearLeftMotor = rearLeftMotor;
m_frontRightMotor = frontRightMotor;
@@ -98,45 +133,15 @@
}
/**
- * Verifies that all motors are nonnull, throwing a NullPointerException if any of them are.
- * The exception's error message will specify all null motors, e.g. {@code
- * NullPointerException("frontLeftMotor, rearRightMotor")}, to give as much information as
- * possible to the programmer.
- *
- * @throws NullPointerException if any of the given motors are null
- */
- @SuppressWarnings({"PMD.AvoidThrowingNullPointerException", "PMD.CyclomaticComplexity"})
- private void verify(SpeedController frontLeft, SpeedController rearLeft,
- SpeedController frontRight, SpeedController rearRightMotor) {
- if (frontLeft != null && rearLeft != null && frontRight != null && rearRightMotor != null) {
- return;
- }
- StringJoiner joiner = new StringJoiner(", ");
- if (frontLeft == null) {
- joiner.add("frontLeftMotor");
- }
- if (rearLeft == null) {
- joiner.add("rearLeftMotor");
- }
- if (frontRight == null) {
- joiner.add("frontRightMotor");
- }
- if (rearRightMotor == null) {
- joiner.add("rearRightMotor");
- }
- throw new NullPointerException(joiner.toString());
- }
-
- /**
* Drive method for Mecanum platform.
*
* <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
* from its angle or rotation rate.
*
- * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
- * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
+ * positive.
*/
@SuppressWarnings("ParameterName")
public void driveCartesian(double ySpeed, double xSpeed, double zRotation) {
@@ -149,45 +154,30 @@
* <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
* from its angle or rotation rate.
*
- * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
- * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
- * @param gyroAngle The current angle reading from the gyro in degrees around the Z axis. Use
- * this to implement field-oriented controls.
+ * positive.
+ * @param gyroAngle The current angle reading from the gyro in degrees around the Z axis. Use this
+ * to implement field-oriented controls.
*/
@SuppressWarnings("ParameterName")
public void driveCartesian(double ySpeed, double xSpeed, double zRotation, double gyroAngle) {
if (!m_reported) {
- HAL.report(tResourceType.kResourceType_RobotDrive,
- tInstances.kRobotDrive2_MecanumCartesian, 4);
+ HAL.report(
+ tResourceType.kResourceType_RobotDrive, tInstances.kRobotDrive2_MecanumCartesian, 4);
m_reported = true;
}
- ySpeed = MathUtil.clamp(ySpeed, -1.0, 1.0);
- ySpeed = applyDeadband(ySpeed, m_deadband);
+ ySpeed = MathUtil.applyDeadband(ySpeed, m_deadband);
+ xSpeed = MathUtil.applyDeadband(xSpeed, m_deadband);
- xSpeed = MathUtil.clamp(xSpeed, -1.0, 1.0);
- xSpeed = applyDeadband(xSpeed, m_deadband);
+ var speeds = driveCartesianIK(ySpeed, xSpeed, zRotation, gyroAngle);
- // Compensate for gyro angle.
- Vector2d input = new Vector2d(ySpeed, xSpeed);
- input.rotate(-gyroAngle);
-
- double[] wheelSpeeds = new double[4];
- wheelSpeeds[MotorType.kFrontLeft.value] = input.x + input.y + zRotation;
- wheelSpeeds[MotorType.kFrontRight.value] = -input.x + input.y - zRotation;
- wheelSpeeds[MotorType.kRearLeft.value] = -input.x + input.y + zRotation;
- wheelSpeeds[MotorType.kRearRight.value] = input.x + input.y - zRotation;
-
- normalize(wheelSpeeds);
-
- m_frontLeftMotor.set(wheelSpeeds[MotorType.kFrontLeft.value] * m_maxOutput);
- m_frontRightMotor.set(wheelSpeeds[MotorType.kFrontRight.value] * m_maxOutput
- * m_rightSideInvertMultiplier);
- m_rearLeftMotor.set(wheelSpeeds[MotorType.kRearLeft.value] * m_maxOutput);
- m_rearRightMotor.set(wheelSpeeds[MotorType.kRearRight.value] * m_maxOutput
- * m_rightSideInvertMultiplier);
+ m_frontLeftMotor.set(speeds.frontLeft * m_maxOutput);
+ m_frontRightMotor.set(speeds.frontRight * m_maxOutput);
+ m_rearLeftMotor.set(speeds.rearLeft * m_maxOutput);
+ m_rearRightMotor.set(speeds.rearRight * m_maxOutput);
feed();
}
@@ -199,9 +189,9 @@
* drives (translation) is independent from its angle or rotation rate.
*
* @param magnitude The robot's speed at a given angle [-1.0..1.0]. Forward is positive.
- * @param angle The angle around the Z axis at which the robot drives in degrees [-180..180].
+ * @param angle The angle around the Z axis at which the robot drives in degrees [-180..180].
* @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
- * positive.
+ * positive.
*/
@SuppressWarnings("ParameterName")
public void drivePolar(double magnitude, double angle, double zRotation) {
@@ -210,26 +200,50 @@
m_reported = true;
}
- driveCartesian(magnitude * Math.sin(angle * (Math.PI / 180.0)),
- magnitude * Math.cos(angle * (Math.PI / 180.0)), zRotation, 0.0);
+ driveCartesian(
+ magnitude * Math.cos(angle * (Math.PI / 180.0)),
+ magnitude * Math.sin(angle * (Math.PI / 180.0)),
+ zRotation,
+ 0.0);
}
/**
- * Gets if the power sent to the right side of the drivetrain is multiplied by -1.
+ * Cartesian inverse kinematics for Mecanum platform.
*
- * @return true if the right side is inverted
+ * <p>Angles are measured clockwise from the positive X axis. The robot's speed is independent
+ * from its angle or rotation rate.
+ *
+ * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive.
+ * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive.
+ * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is
+ * positive.
+ * @param gyroAngle The current angle reading from the gyro in degrees around the Z axis. Use this
+ * to implement field-oriented controls.
+ * @return Wheel speeds.
*/
- public boolean isRightSideInverted() {
- return m_rightSideInvertMultiplier == -1.0;
- }
+ @SuppressWarnings("ParameterName")
+ public static WheelSpeeds driveCartesianIK(
+ double ySpeed, double xSpeed, double zRotation, double gyroAngle) {
+ ySpeed = MathUtil.clamp(ySpeed, -1.0, 1.0);
+ xSpeed = MathUtil.clamp(xSpeed, -1.0, 1.0);
- /**
- * Sets if the power sent to the right side of the drivetrain should be multiplied by -1.
- *
- * @param rightSideInverted true if right side power should be multiplied by -1
- */
- public void setRightSideInverted(boolean rightSideInverted) {
- m_rightSideInvertMultiplier = rightSideInverted ? -1.0 : 1.0;
+ // Compensate for gyro angle.
+ Vector2d input = new Vector2d(ySpeed, xSpeed);
+ input.rotate(-gyroAngle);
+
+ double[] wheelSpeeds = new double[4];
+ wheelSpeeds[MotorType.kFrontLeft.value] = input.x + input.y + zRotation;
+ wheelSpeeds[MotorType.kFrontRight.value] = input.x - input.y - zRotation;
+ wheelSpeeds[MotorType.kRearLeft.value] = input.x - input.y + zRotation;
+ wheelSpeeds[MotorType.kRearRight.value] = input.x + input.y - zRotation;
+
+ normalize(wheelSpeeds);
+
+ return new WheelSpeeds(
+ wheelSpeeds[MotorType.kFrontLeft.value],
+ wheelSpeeds[MotorType.kFrontRight.value],
+ wheelSpeeds[MotorType.kRearLeft.value],
+ wheelSpeeds[MotorType.kRearRight.value]);
}
@Override
@@ -251,17 +265,16 @@
builder.setSmartDashboardType("MecanumDrive");
builder.setActuator(true);
builder.setSafeState(this::stopMotor);
- builder.addDoubleProperty("Front Left Motor Speed",
- m_frontLeftMotor::get,
- m_frontLeftMotor::set);
- builder.addDoubleProperty("Front Right Motor Speed",
- () -> m_frontRightMotor.get() * m_rightSideInvertMultiplier,
- value -> m_frontRightMotor.set(value * m_rightSideInvertMultiplier));
- builder.addDoubleProperty("Rear Left Motor Speed",
- m_rearLeftMotor::get,
- m_rearLeftMotor::set);
- builder.addDoubleProperty("Rear Right Motor Speed",
- () -> m_rearRightMotor.get() * m_rightSideInvertMultiplier,
- value -> m_rearRightMotor.set(value * m_rightSideInvertMultiplier));
+ builder.addDoubleProperty(
+ "Front Left Motor Speed", m_frontLeftMotor::get, m_frontLeftMotor::set);
+ builder.addDoubleProperty(
+ "Front Right Motor Speed",
+ () -> m_frontRightMotor.get(),
+ value -> m_frontRightMotor.set(value));
+ builder.addDoubleProperty("Rear Left Motor Speed", m_rearLeftMotor::get, m_rearLeftMotor::set);
+ builder.addDoubleProperty(
+ "Rear Right Motor Speed",
+ () -> m_rearRightMotor.get(),
+ value -> m_rearRightMotor.set(value));
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java
index 785a0c5..569f94c 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/RobotDriveBase.java
@@ -1,17 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.drive;
+import edu.wpi.first.math.MathUtil;
import edu.wpi.first.wpilibj.MotorSafety;
-/**
- * Common base class for drive platforms.
- */
+/** Common base class for drive platforms. */
public abstract class RobotDriveBase extends MotorSafety {
public static final double kDefaultDeadband = 0.02;
public static final double kDefaultMaxOutput = 1.0;
@@ -19,14 +15,16 @@
protected double m_deadband = kDefaultDeadband;
protected double m_maxOutput = kDefaultMaxOutput;
- /**
- * The location of a motor on the robot for the purpose of driving.
- */
+ /** The location of a motor on the robot for the purpose of driving. */
public enum MotorType {
- kFrontLeft(0), kFrontRight(1), kRearLeft(2), kRearRight(3), kLeft(0),
- kRight(1), kBack(2);
+ kFrontLeft(0),
+ kFrontRight(1),
+ kRearLeft(2),
+ kRearRight(3),
+ kLeft(0),
+ kRight(1),
+ kBack(2);
- @SuppressWarnings("MemberName")
public final int value;
MotorType(int value) {
@@ -34,9 +32,7 @@
}
}
- /**
- * RobotDriveBase constructor.
- */
+ /** RobotDriveBase constructor. */
public RobotDriveBase() {
setSafetyEnabled(true);
}
@@ -45,8 +41,8 @@
* Sets the deadband applied to the drive inputs (e.g., joystick values).
*
* <p>The default value is {@value #kDefaultDeadband}. Inputs smaller than the deadband are set to
- * 0.0 while inputs larger than the deadband are scaled from 0.0 to 1.0. See
- * {@link #applyDeadband}.
+ * 0.0 while inputs larger than the deadband are scaled from 0.0 to 1.0. See {@link
+ * edu.wpi.first.math.MathUtil#applyDeadband}.
*
* @param deadband The deadband to set.
*/
@@ -85,25 +81,22 @@
* Returns 0.0 if the given value is within the specified range around zero. The remaining range
* between the deadband and 1.0 is scaled from 0.0 to 1.0.
*
- * @param value value to clip
+ * @param value value to clip
* @param deadband range around zero
+ * @return The value after the deadband is applied.
+ * @deprecated Use MathUtil.applyDeadband(double,double).
*/
- protected double applyDeadband(double value, double deadband) {
- if (Math.abs(value) > deadband) {
- if (value > 0.0) {
- return (value - deadband) / (1.0 - deadband);
- } else {
- return (value + deadband) / (1.0 - deadband);
- }
- } else {
- return 0.0;
- }
+ @Deprecated(since = "2021", forRemoval = true)
+ protected static double applyDeadband(double value, double deadband) {
+ return MathUtil.applyDeadband(value, deadband);
}
/**
* Normalize all wheel speeds if the magnitude of any wheel is greater than 1.0.
+ *
+ * @param wheelSpeeds List of wheel speeds to normalize.
*/
- protected void normalize(double[] wheelSpeeds) {
+ protected static void normalize(double[] wheelSpeeds) {
double maxMagnitude = Math.abs(wheelSpeeds[0]);
for (int i = 1; i < wheelSpeeds.length; i++) {
double temp = Math.abs(wheelSpeeds[i]);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/Vector2d.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/Vector2d.java
index 2b1f839..728cc83 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/Vector2d.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/Vector2d.java
@@ -1,23 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.drive;
-/**
- * This is a 2D vector struct that supports basic vector operations.
- */
-@SuppressWarnings("MemberName")
+/** This is a 2D vector struct that supports basic vector operations. */
public class Vector2d {
+ @SuppressWarnings("MemberName")
public double x;
+
+ @SuppressWarnings("MemberName")
public double y;
public Vector2d() {}
- @SuppressWarnings("ParameterName")
public Vector2d(double x, double y) {
this.x = x;
this.y = y;
@@ -42,6 +38,7 @@
* Returns dot product of this vector with argument.
*
* @param vec Vector with which to perform dot product.
+ * @return Dot product of this vector with argument.
*/
public double dot(Vector2d vec) {
return x * vec.x + y * vec.y;
@@ -49,6 +46,8 @@
/**
* Returns magnitude of vector.
+ *
+ * @return Magnitude of vector.
*/
public double magnitude() {
return Math.sqrt(x * x + y * y);
@@ -58,6 +57,7 @@
* Returns scalar projection of this vector onto argument.
*
* @param vec Vector onto which to project this vector.
+ * @return scalar projection of this vector onto argument.
*/
public double scalarProject(Vector2d vec) {
return dot(vec) / vec.magnitude();
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/Filter.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/Filter.java
deleted file mode 100644
index 257d36a..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/Filter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.filters;
-
-import edu.wpi.first.wpilibj.PIDSource;
-import edu.wpi.first.wpilibj.PIDSourceType;
-
-/**
- * Superclass for filters.
- *
- * @deprecated This class is no longer used.
- */
-@Deprecated(since = "2020", forRemoval = true)
-public abstract class Filter implements PIDSource {
- private final PIDSource m_source;
-
- public Filter(PIDSource source) {
- m_source = source;
- }
-
- @Override
- public void setPIDSourceType(PIDSourceType pidSource) {
- m_source.setPIDSourceType(pidSource);
- }
-
- @Override
- public PIDSourceType getPIDSourceType() {
- return m_source.getPIDSourceType();
- }
-
- @Override
- public abstract double pidGet();
-
- /**
- * Returns the current filter estimate without also inserting new data as pidGet() would do.
- *
- * @return The current filter estimate
- */
- public abstract double get();
-
- /**
- * Reset the filter state.
- */
- public abstract void reset();
-
- /**
- * Calls PIDGet() of source.
- *
- * @return Current value of source
- */
- protected double pidGetSource() {
- return m_source.pidGet();
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/LinearDigitalFilter.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/LinearDigitalFilter.java
deleted file mode 100644
index cbeb4aa..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/filters/LinearDigitalFilter.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.filters;
-
-import java.util.Arrays;
-
-import edu.wpi.first.hal.FRCNetComm.tResourceType;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.PIDSource;
-import edu.wpi.first.wpiutil.CircularBuffer;
-
-/**
- * This class implements a linear, digital filter. All types of FIR and IIR filters are supported.
- * Static factory methods are provided to create commonly used types of filters.
- *
- * <p>Filters are of the form: y[n] = (b0*x[n] + b1*x[n-1] + ... + bP*x[n-P]) - (a0*y[n-1] +
- * a2*y[n-2] + ... + aQ*y[n-Q])
- *
- * <p>Where: y[n] is the output at time "n" x[n] is the input at time "n" y[n-1] is the output from
- * the LAST time step ("n-1") x[n-1] is the input from the LAST time step ("n-1") b0...bP are the
- * "feedforward" (FIR) gains a0...aQ are the "feedback" (IIR) gains IMPORTANT! Note the "-" sign in
- * front of the feedback term! This is a common convention in signal processing.
- *
- * <p>What can linear filters do? Basically, they can filter, or diminish, the effects of
- * undesirable input frequencies. High frequencies, or rapid changes, can be indicative of sensor
- * noise or be otherwise undesirable. A "low pass" filter smooths out the signal, reducing the
- * impact of these high frequency components. Likewise, a "high pass" filter gets rid of
- * slow-moving signal components, letting you detect large changes more easily.
- *
- * <p>Example FRC applications of filters: - Getting rid of noise from an analog sensor input (note:
- * the roboRIO's FPGA can do this faster in hardware) - Smoothing out joystick input to prevent the
- * wheels from slipping or the robot from tipping - Smoothing motor commands so that unnecessary
- * strain isn't put on electrical or mechanical components - If you use clever gains, you can make a
- * PID controller out of this class!
- *
- * <p>For more on filters, I highly recommend the following articles: http://en.wikipedia
- * .org/wiki/Linear_filter http://en.wikipedia.org/wiki/Iir_filter http://en.wikipedia
- * .org/wiki/Fir_filter
- *
- * <p>Note 1: PIDGet() should be called by the user on a known, regular period. You can set up a
- * Notifier to do this (look at the WPILib PIDController class), or do it "inline" with code in a
- * periodic function.
- *
- * <p>Note 2: For ALL filters, gains are necessarily a function of frequency. If you make a filter
- * that works well for you at, say, 100Hz, you will most definitely need to adjust the gains if you
- * then want to run it at 200Hz! Combining this with Note 1 - the impetus is on YOU as a developer
- * to make sure PIDGet() gets called at the desired, constant frequency!
- *
- * @deprecated Use LinearFilter class instead.
- */
-@Deprecated
-public class LinearDigitalFilter extends Filter {
- private static int instances;
-
- private final CircularBuffer m_inputs;
- private final CircularBuffer m_outputs;
- private final double[] m_inputGains;
- private final double[] m_outputGains;
-
- /**
- * Create a linear FIR or IIR filter.
- *
- * @param source The PIDSource object that is used to get values
- * @param ffGains The "feed forward" or FIR gains
- * @param fbGains The "feed back" or IIR gains
- */
- public LinearDigitalFilter(PIDSource source, double[] ffGains,
- double[] fbGains) {
- super(source);
- m_inputs = new CircularBuffer(ffGains.length);
- m_outputs = new CircularBuffer(fbGains.length);
- m_inputGains = Arrays.copyOf(ffGains, ffGains.length);
- m_outputGains = Arrays.copyOf(fbGains, fbGains.length);
-
- instances++;
- HAL.report(tResourceType.kResourceType_LinearFilter, instances);
- }
-
- /**
- * Creates a one-pole IIR low-pass filter of the form: y[n] = (1-gain)*x[n] + gain*y[n-1] where
- * gain = e^(-dt / T), T is the time constant in seconds.
- *
- * <p>This filter is stable for time constants greater than zero.
- *
- * @param source The PIDSource object that is used to get values
- * @param timeConstant The discrete-time time constant in seconds
- * @param period The period in seconds between samples taken by the user
- */
- public static LinearDigitalFilter singlePoleIIR(PIDSource source,
- double timeConstant,
- double period) {
- double gain = Math.exp(-period / timeConstant);
- double[] ffGains = {1.0 - gain};
- double[] fbGains = {-gain};
-
- return new LinearDigitalFilter(source, ffGains, fbGains);
- }
-
- /**
- * Creates a first-order high-pass filter of the form: y[n] = gain*x[n] + (-gain)*x[n-1] +
- * gain*y[n-1] where gain = e^(-dt / T), T is the time constant in seconds.
- *
- * <p>This filter is stable for time constants greater than zero.
- *
- * @param source The PIDSource object that is used to get values
- * @param timeConstant The discrete-time time constant in seconds
- * @param period The period in seconds between samples taken by the user
- */
- public static LinearDigitalFilter highPass(PIDSource source,
- double timeConstant,
- double period) {
- double gain = Math.exp(-period / timeConstant);
- double[] ffGains = {gain, -gain};
- double[] fbGains = {-gain};
-
- return new LinearDigitalFilter(source, ffGains, fbGains);
- }
-
- /**
- * Creates a K-tap FIR moving average filter of the form: y[n] = 1/k * (x[k] + x[k-1] + ... +
- * x[0]).
- *
- * <p>This filter is always stable.
- *
- * @param source The PIDSource object that is used to get values
- * @param taps The number of samples to average over. Higher = smoother but slower
- * @throws IllegalArgumentException if number of taps is less than 1
- */
- public static LinearDigitalFilter movingAverage(PIDSource source, int taps) {
- if (taps <= 0) {
- throw new IllegalArgumentException("Number of taps was not at least 1");
- }
-
- double[] ffGains = new double[taps];
- for (int i = 0; i < ffGains.length; i++) {
- ffGains[i] = 1.0 / taps;
- }
-
- double[] fbGains = new double[0];
-
- return new LinearDigitalFilter(source, ffGains, fbGains);
- }
-
- @Override
- public double get() {
- double retVal = 0.0;
-
- // Calculate the new value
- for (int i = 0; i < m_inputGains.length; i++) {
- retVal += m_inputs.get(i) * m_inputGains[i];
- }
- for (int i = 0; i < m_outputGains.length; i++) {
- retVal -= m_outputs.get(i) * m_outputGains[i];
- }
-
- return retVal;
- }
-
- @Override
- public void reset() {
- m_inputs.clear();
- m_outputs.clear();
- }
-
- /**
- * Calculates the next value of the filter.
- *
- * @return The filtered value at this step
- */
- @Override
- public double pidGet() {
- double retVal = 0.0;
-
- // Rotate the inputs
- m_inputs.addFirst(pidGetSource());
-
- // Calculate the new value
- for (int i = 0; i < m_inputGains.length; i++) {
- retVal += m_inputs.get(i) * m_inputGains[i];
- }
- for (int i = 0; i < m_outputGains.length; i++) {
- retVal -= m_outputs.get(i) * m_outputGains[i];
- }
-
- // Rotate the outputs
- m_outputs.addFirst(retVal);
-
- return retVal;
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Accelerometer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Accelerometer.java
index 81086d4..de2780f 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Accelerometer.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Accelerometer.java
@@ -1,25 +1,23 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2014-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.interfaces;
-/**
- * Interface for 3-axis accelerometers.
- */
+/** Interface for 3-axis accelerometers. */
public interface Accelerometer {
enum Range {
- k2G, k4G, k8G, k16G
+ k2G,
+ k4G,
+ k8G,
+ k16G
}
/**
* Common interface for setting the measuring range of an accelerometer.
*
* @param range The maximum acceleration, positive or negative, that the accelerometer will
- * measure. Not all accelerometers support all ranges.
+ * measure. Not all accelerometers support all ranges.
*/
void setRange(Range range);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Gyro.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Gyro.java
index 3bac20f..27377be 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Gyro.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Gyro.java
@@ -1,22 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2014-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.interfaces;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
+import edu.wpi.first.math.geometry.Rotation2d;
-/**
- * Interface for yaw rate gyros.
- */
+/** Interface for yaw rate gyros. */
public interface Gyro extends AutoCloseable {
/**
* Calibrate the gyro. It's important to make sure that the robot is not moving while the
- * calibration is in progress, this is typically done when the robot is first turned on while
- * it's sitting at rest before the match starts.
+ * calibration is in progress, this is typically done when the robot is first turned on while it's
+ * sitting at rest before the match starts.
*/
void calibrate();
@@ -30,11 +25,11 @@
* Return the heading of the robot in degrees.
*
* <p>The angle is continuous, that is it will continue from 360 to 361 degrees. This allows
- * algorithms that wouldn't want to see a discontinuity in the gyro output as it sweeps past
- * from 360 to 0 on the second time around.
+ * algorithms that wouldn't want to see a discontinuity in the gyro output as it sweeps past from
+ * 360 to 0 on the second time around.
*
- * <p>The angle is expected to increase as the gyro turns clockwise when looked
- * at from the top. It needs to follow the NED axis convention.
+ * <p>The angle is expected to increase as the gyro turns clockwise when looked at from the top.
+ * It needs to follow the NED axis convention.
*
* <p>This heading is based on integration of the returned rate from the gyro.
*
@@ -47,27 +42,26 @@
*
* <p>The rate is based on the most recent reading of the gyro analog value
*
- * <p>The rate is expected to be positive as the gyro turns clockwise when looked
- * at from the top. It needs to follow the NED axis convention.
+ * <p>The rate is expected to be positive as the gyro turns clockwise when looked at from the top.
+ * It needs to follow the NED axis convention.
*
* @return the current rate in degrees per second
*/
double getRate();
/**
- * Return the heading of the robot as a {@link edu.wpi.first.wpilibj.geometry.Rotation2d}.
+ * Return the heading of the robot as a {@link edu.wpi.first.math.geometry.Rotation2d}.
*
* <p>The angle is continuous, that is it will continue from 360 to 361 degrees. This allows
- * algorithms that wouldn't want to see a discontinuity in the gyro output as it sweeps past
- * from 360 to 0 on the second time around.
+ * algorithms that wouldn't want to see a discontinuity in the gyro output as it sweeps past from
+ * 360 to 0 on the second time around.
*
- * <p>The angle is expected to increase as the gyro turns counterclockwise
- * when looked at from the top. It needs to follow the NWU axis convention.
+ * <p>The angle is expected to increase as the gyro turns counterclockwise when looked at from the
+ * top. It needs to follow the NWU axis convention.
*
* <p>This heading is based on integration of the returned rate from the gyro.
*
- * @return the current heading of the robot as a
- * {@link edu.wpi.first.wpilibj.geometry.Rotation2d}.
+ * @return the current heading of the robot as a {@link edu.wpi.first.math.geometry.Rotation2d}.
*/
default Rotation2d getRotation2d() {
return Rotation2d.fromDegrees(-getAngle());
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Potentiometer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Potentiometer.java
deleted file mode 100644
index ea5c1e6..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/interfaces/Potentiometer.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.interfaces;
-
-import edu.wpi.first.wpilibj.PIDSource;
-
-/**
- * Interface for a Potentiometer.
- */
-public interface Potentiometer extends PIDSource {
- double get();
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindow.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindow.java
index 6570780..ff3e8ef 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindow.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/livewindow/LiveWindow.java
@@ -1,22 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.livewindow;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
-import edu.wpi.first.wpilibj.Sendable;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableRegistry;
+import edu.wpi.first.wpilibj.smartdashboard.SendableBuilderImpl;
/**
- * The LiveWindow class is the public interface for putting sensors and actuators on the
- * LiveWindow.
+ * The LiveWindow class is the public interface for putting sensors and actuators on the LiveWindow.
*/
public class LiveWindow {
private static class Component {
@@ -36,6 +32,10 @@
private static Runnable enabledListener;
private static Runnable disabledListener;
+ static {
+ SendableRegistry.setLiveWindowBuilderFactory(() -> new SendableBuilderImpl());
+ }
+
private static Component getOrAdd(Sendable sendable) {
Component data = (Component) SendableRegistry.getData(sendable, dataHandle);
if (data == null) {
@@ -62,12 +62,17 @@
}
/**
- * Set the enabled state of LiveWindow. If it's being enabled, turn off the scheduler and remove
- * all the commands from the queue and enable all the components registered for LiveWindow. If
- * it's being disabled, stop all the registered components and reenable the scheduler. TODO: add
- * code to disable PID loops when enabling LiveWindow. The commands should reenable the PID loops
- * themselves when they get rescheduled. This prevents arms from starting to move around, etc.
- * after a period of adjusting them in LiveWindow mode.
+ * Set the enabled state of LiveWindow.
+ *
+ * <p>If it's being enabled, turn off the scheduler and remove all the commands from the queue and
+ * enable all the components registered for LiveWindow. If it's being disabled, stop all the
+ * registered components and reenable the scheduler.
+ *
+ * <p>TODO: add code to disable PID loops when enabling LiveWindow. The commands should reenable
+ * the PID loops themselves when they get rescheduled. This prevents arms from starting to move
+ * around, etc. after a period of adjusting them in LiveWindow mode.
+ *
+ * @param enabled True to enable LiveWindow.
*/
public static synchronized void setEnabled(boolean enabled) {
if (liveWindowEnabled != enabled) {
@@ -81,9 +86,11 @@
}
} else {
System.out.println("stopping live window mode.");
- SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
- cbdata.builder.stopLiveWindowMode();
- });
+ SendableRegistry.foreachLiveWindow(
+ dataHandle,
+ cbdata -> {
+ ((SendableBuilderImpl) cbdata.builder).stopLiveWindowMode();
+ });
if (disabledListener != null) {
disabledListener.run();
}
@@ -112,76 +119,77 @@
getOrAdd(sendable).m_telemetryEnabled = false;
}
- /**
- * Disable ALL telemetry.
- */
+ /** Disable ALL telemetry. */
public static synchronized void disableAllTelemetry() {
telemetryEnabled = false;
- SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
- if (cbdata.data == null) {
- cbdata.data = new Component();
- }
- ((Component) cbdata.data).m_telemetryEnabled = false;
- });
+ SendableRegistry.foreachLiveWindow(
+ dataHandle,
+ cbdata -> {
+ if (cbdata.data == null) {
+ cbdata.data = new Component();
+ }
+ ((Component) cbdata.data).m_telemetryEnabled = false;
+ });
}
/**
* Tell all the sensors to update (send) their values.
*
- * <p>Actuators are handled through callbacks on their value changing from the
- * SmartDashboard widgets.
+ * <p>Actuators are handled through callbacks on their value changing from the SmartDashboard
+ * widgets.
*/
- @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
public static synchronized void updateValues() {
// Only do this if either LiveWindow mode or telemetry is enabled.
if (!liveWindowEnabled && !telemetryEnabled) {
return;
}
- SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
- if (cbdata.sendable == null || cbdata.parent != null) {
- return;
- }
+ SendableRegistry.foreachLiveWindow(
+ dataHandle,
+ cbdata -> {
+ if (cbdata.sendable == null || cbdata.parent != null) {
+ return;
+ }
- if (cbdata.data == null) {
- cbdata.data = new Component();
- }
+ if (cbdata.data == null) {
+ cbdata.data = new Component();
+ }
- Component component = (Component) cbdata.data;
+ Component component = (Component) cbdata.data;
- if (!liveWindowEnabled && !component.m_telemetryEnabled) {
- return;
- }
+ if (!liveWindowEnabled && !component.m_telemetryEnabled) {
+ return;
+ }
- if (component.m_firstTime) {
- // By holding off creating the NetworkTable entries, it allows the
- // components to be redefined. This allows default sensor and actuator
- // values to be created that are replaced with the custom names from
- // users calling setName.
- if (cbdata.name.isEmpty()) {
- return;
- }
- NetworkTable ssTable = liveWindowTable.getSubTable(cbdata.subsystem);
- NetworkTable table;
- // Treat name==subsystem as top level of subsystem
- if (cbdata.name.equals(cbdata.subsystem)) {
- table = ssTable;
- } else {
- table = ssTable.getSubTable(cbdata.name);
- }
- table.getEntry(".name").setString(cbdata.name);
- cbdata.builder.setTable(table);
- cbdata.sendable.initSendable(cbdata.builder);
- ssTable.getEntry(".type").setString("LW Subsystem");
+ if (component.m_firstTime) {
+ // By holding off creating the NetworkTable entries, it allows the
+ // components to be redefined. This allows default sensor and actuator
+ // values to be created that are replaced with the custom names from
+ // users calling setName.
+ if (cbdata.name.isEmpty()) {
+ return;
+ }
+ NetworkTable ssTable = liveWindowTable.getSubTable(cbdata.subsystem);
+ NetworkTable table;
+ // Treat name==subsystem as top level of subsystem
+ if (cbdata.name.equals(cbdata.subsystem)) {
+ table = ssTable;
+ } else {
+ table = ssTable.getSubTable(cbdata.name);
+ }
+ table.getEntry(".name").setString(cbdata.name);
+ ((SendableBuilderImpl) cbdata.builder).setTable(table);
+ cbdata.sendable.initSendable(cbdata.builder);
+ ssTable.getEntry(".type").setString("LW Subsystem");
- component.m_firstTime = false;
- }
+ component.m_firstTime = false;
+ }
- if (startLiveWindow) {
- cbdata.builder.startLiveWindowMode();
- }
- cbdata.builder.updateTable();
- });
+ if (startLiveWindow) {
+ ((SendableBuilderImpl) cbdata.builder).startLiveWindowMode();
+ }
+ cbdata.builder.update();
+ });
startLiveWindow = false;
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/DMC60.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/DMC60.java
new file mode 100644
index 0000000..c003b56
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/DMC60.java
@@ -0,0 +1,45 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * Digilent DMC 60 Motor Controller.
+ *
+ * <p>Note that the DMC uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the DMC 60 User Manual available from
+ * Digilent.
+ *
+ * <ul>
+ * <li>2.004ms = full "forward"
+ * <li>1.520ms = the "high end" of the deadband range
+ * <li>1.500ms = center of the deadband range (off)
+ * <li>1.480ms = the "low end" of the deadband range
+ * <li>0.997ms = full "reverse"
+ * </ul>
+ */
+public class DMC60 extends PWMMotorController {
+ /**
+ * Constructor.
+ *
+ * @param channel The PWM channel that the DMC60 is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public DMC60(final int channel) {
+ super("DMC60", channel);
+
+ m_pwm.setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_DigilentDMC60, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Jaguar.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Jaguar.java
new file mode 100644
index 0000000..32e6417
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Jaguar.java
@@ -0,0 +1,44 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * Texas Instruments / Vex Robotics Jaguar Motor Controller as a PWM device.
+ *
+ * <p>Note that the Jaguar uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the Jaguar User Manual available from Vex.
+ *
+ * <ul>
+ * <li>2.310ms = full "forward"
+ * <li>1.550ms = the "high end" of the deadband range
+ * <li>1.507ms = center of the deadband range (off)
+ * <li>1.454ms = the "low end" of the deadband range
+ * <li>0.697ms = full "reverse"
+ * </ul>
+ */
+public class Jaguar extends PWMMotorController {
+ /**
+ * Constructor.
+ *
+ * @param channel The PWM channel that the Jaguar is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public Jaguar(final int channel) {
+ super("Jaguar", channel);
+
+ m_pwm.setBounds(2.31, 1.55, 1.507, 1.454, 0.697);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_Jaguar, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/MotorController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/MotorController.java
new file mode 100644
index 0000000..ac82afa
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/MotorController.java
@@ -0,0 +1,71 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.wpilibj.RobotController;
+import edu.wpi.first.wpilibj.SpeedController;
+
+/** Interface for motor controlling devices. */
+@SuppressWarnings("removal")
+public interface MotorController extends SpeedController {
+ /**
+ * Common interface for setting the speed of a motor controller.
+ *
+ * @param speed The speed to set. Value should be between -1.0 and 1.0.
+ */
+ @Override
+ void set(double speed);
+
+ /**
+ * Sets the voltage output of the MotorController. Compensates for the current bus voltage to
+ * ensure that the desired voltage is output even if the battery voltage is below 12V - highly
+ * useful when the voltage outputs are "meaningful" (e.g. they come from a feedforward
+ * calculation).
+ *
+ * <p>NOTE: This function *must* be called regularly in order for voltage compensation to work
+ * properly - unlike the ordinary set function, it is not "set it and forget it."
+ *
+ * @param outputVolts The voltage to output.
+ */
+ @Override
+ default void setVoltage(double outputVolts) {
+ set(outputVolts / RobotController.getBatteryVoltage());
+ }
+
+ /**
+ * Common interface for getting the current set speed of a motor controller.
+ *
+ * @return The current set speed. Value is between -1.0 and 1.0.
+ */
+ @Override
+ double get();
+
+ /**
+ * Common interface for inverting direction of a motor controller.
+ *
+ * @param isInverted The state of inversion true is inverted.
+ */
+ @Override
+ void setInverted(boolean isInverted);
+
+ /**
+ * Common interface for returning if a motor controller is in the inverted state or not.
+ *
+ * @return isInverted The state of the inversion true is inverted.
+ */
+ @Override
+ boolean getInverted();
+
+ /** Disable the motor controller. */
+ @Override
+ void disable();
+
+ /**
+ * Stops motor movement. Motor can be moved again by calling set without having to re-enable the
+ * motor.
+ */
+ @Override
+ void stopMotor();
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/MotorControllerGroup.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/MotorControllerGroup.java
new file mode 100644
index 0000000..714aac5
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/MotorControllerGroup.java
@@ -0,0 +1,96 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
+import java.util.Arrays;
+
+/** Allows multiple {@link MotorController} objects to be linked together. */
+public class MotorControllerGroup implements MotorController, Sendable, AutoCloseable {
+ private boolean m_isInverted;
+ private final MotorController[] m_motorControllers;
+ private static int instances;
+
+ /**
+ * Create a new MotorControllerGroup with the provided MotorControllers.
+ *
+ * @param motorController The first MotorController to add
+ * @param motorControllers The MotorControllers to add
+ */
+ public MotorControllerGroup(
+ MotorController motorController, MotorController... motorControllers) {
+ m_motorControllers = new MotorController[motorControllers.length + 1];
+ m_motorControllers[0] = motorController;
+ System.arraycopy(motorControllers, 0, m_motorControllers, 1, motorControllers.length);
+ init();
+ }
+
+ public MotorControllerGroup(MotorController[] motorControllers) {
+ m_motorControllers = Arrays.copyOf(motorControllers, motorControllers.length);
+ init();
+ }
+
+ private void init() {
+ for (MotorController controller : m_motorControllers) {
+ SendableRegistry.addChild(this, controller);
+ }
+ instances++;
+ SendableRegistry.addLW(this, "MotorControllerGroup", instances);
+ }
+
+ @Override
+ public void close() {
+ SendableRegistry.remove(this);
+ }
+
+ @Override
+ public void set(double speed) {
+ for (MotorController motorController : m_motorControllers) {
+ motorController.set(m_isInverted ? -speed : speed);
+ }
+ }
+
+ @Override
+ public double get() {
+ if (m_motorControllers.length > 0) {
+ return m_motorControllers[0].get() * (m_isInverted ? -1 : 1);
+ }
+ return 0.0;
+ }
+
+ @Override
+ public void setInverted(boolean isInverted) {
+ m_isInverted = isInverted;
+ }
+
+ @Override
+ public boolean getInverted() {
+ return m_isInverted;
+ }
+
+ @Override
+ public void disable() {
+ for (MotorController motorController : m_motorControllers) {
+ motorController.disable();
+ }
+ }
+
+ @Override
+ public void stopMotor() {
+ for (MotorController motorController : m_motorControllers) {
+ motorController.stopMotor();
+ }
+ }
+
+ @Override
+ public void initSendable(SendableBuilder builder) {
+ builder.setSmartDashboardType("Motor Controller");
+ builder.setActuator(true);
+ builder.setSafeState(this::stopMotor);
+ builder.addDoubleProperty("Value", this::get, this::set);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/NidecBrushless.java
similarity index 66%
rename from wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java
rename to wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/NidecBrushless.java
index 9d1011b..13daf68 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/NidecBrushless.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/NidecBrushless.java
@@ -1,22 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
-package edu.wpi.first.wpilibj;
+package edu.wpi.first.wpilibj.motorcontrol;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+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.DigitalOutput;
+import edu.wpi.first.wpilibj.MotorSafety;
+import edu.wpi.first.wpilibj.PWM;
-/**
- * Nidec Brushless Motor.
- */
-public class NidecBrushless extends MotorSafety implements SpeedController, Sendable,
- AutoCloseable {
+/** Nidec Brushless Motor. */
+public class NidecBrushless extends MotorSafety
+ implements MotorController, Sendable, AutoCloseable {
private boolean m_isInverted;
private final DigitalOutput m_dio;
private final PWM m_pwm;
@@ -26,10 +25,10 @@
/**
* Constructor.
*
- * @param pwmChannel The PWM channel that the Nidec Brushless controller is attached to.
- * 0-9 are on-board, 10-19 are on the MXP port
- * @param dioChannel The DIO channel that the Nidec Brushless controller is attached to.
- * 0-9 are on-board, 10-25 are on the MXP port
+ * @param pwmChannel The PWM channel that the Nidec Brushless controller is attached to. 0-9 are
+ * on-board, 10-19 are on the MXP port
+ * @param dioChannel The DIO channel that the Nidec Brushless controller is attached to. 0-9 are
+ * on-board, 10-25 are on the MXP port
*/
public NidecBrushless(final int pwmChannel, final int dioChannel) {
setSafetyEnabled(false);
@@ -95,16 +94,6 @@
}
/**
- * Write out the PID value as seen in the PIDOutput base object.
- *
- * @param output Write out the PWM value as was found in the PIDController
- */
- @Override
- public void pidWrite(double output) {
- set(output);
- }
-
- /**
* Stop the motor. This is called by the MotorSafety object when it has a timeout for this PWM and
* needs to stop it from running. Calling set() will re-enable the motor.
*/
@@ -119,10 +108,7 @@
return "Nidec " + getChannel();
}
- /**
- * Disable the motor. The enable() function must be called to re-enable
- * the motor.
- */
+ /** Disable the motor. The enable() function must be called to re-enable the motor. */
@Override
public void disable() {
m_disabled = true;
@@ -131,8 +117,8 @@
}
/**
- * Re-enable the motor after disable() has been called. The set()
- * function must be called to set a new motor speed.
+ * Re-enable the motor after disable() has been called. The set() function must be called to set a
+ * new motor speed.
*/
public void enable() {
m_disabled = false;
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMMotorController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMMotorController.java
new file mode 100644
index 0000000..d33fb01
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMMotorController.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.wpilibj.motorcontrol;
+
+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.MotorSafety;
+import edu.wpi.first.wpilibj.PWM;
+
+/** Common base class for all PWM Motor Controllers. */
+public abstract class PWMMotorController extends MotorSafety
+ implements MotorController, Sendable, AutoCloseable {
+ private boolean m_isInverted;
+ protected PWM m_pwm;
+
+ /**
+ * Constructor.
+ *
+ * @param name Name to use for SendableRegistry
+ * @param channel The PWM channel that the controller is attached to. 0-9 are on-board, 10-19 are
+ * on the MXP port
+ */
+ protected PWMMotorController(final String name, final int channel) {
+ m_pwm = new PWM(channel, false);
+ SendableRegistry.addLW(this, name, channel);
+ }
+
+ /** Free the resource associated with the PWM channel and set the value to 0. */
+ @Override
+ public void close() {
+ SendableRegistry.remove(this);
+ m_pwm.close();
+ }
+
+ /**
+ * Set the PWM value.
+ *
+ * <p>The PWM value is set using a range of -1.0 to 1.0, appropriately scaling the value for the
+ * FPGA.
+ *
+ * @param speed The speed value between -1.0 and 1.0 to set.
+ */
+ @Override
+ public void set(double speed) {
+ m_pwm.setSpeed(m_isInverted ? -speed : speed);
+ feed();
+ }
+
+ /**
+ * Get the recently set value of the PWM. This value is affected by the inversion property. If you
+ * want the value that is sent directly to the MotorController, use {@link
+ * edu.wpi.first.wpilibj.PWM#getSpeed()} instead.
+ *
+ * @return The most recently set value for the PWM between -1.0 and 1.0.
+ */
+ @Override
+ public double get() {
+ return m_pwm.getSpeed() * (m_isInverted ? -1.0 : 1.0);
+ }
+
+ @Override
+ public void setInverted(boolean isInverted) {
+ m_isInverted = isInverted;
+ }
+
+ @Override
+ public boolean getInverted() {
+ return m_isInverted;
+ }
+
+ @Override
+ public void disable() {
+ m_pwm.setDisabled();
+ }
+
+ @Override
+ public void stopMotor() {
+ disable();
+ }
+
+ @Override
+ public String getDescription() {
+ return "PWM " + getChannel();
+ }
+
+ /**
+ * Gets the backing PWM handle.
+ *
+ * @return The pwm handle.
+ */
+ public int getPwmHandle() {
+ return m_pwm.getHandle();
+ }
+
+ /**
+ * Gets the PWM channel number.
+ *
+ * @return The channel number.
+ */
+ public int getChannel() {
+ return m_pwm.getChannel();
+ }
+
+ @Override
+ public void initSendable(SendableBuilder builder) {
+ builder.setSmartDashboardType("Motor Controller");
+ builder.setActuator(true);
+ builder.setSafeState(this::disable);
+ builder.addDoubleProperty("Value", this::get, this::set);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMSparkMax.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMSparkMax.java
new file mode 100644
index 0000000..e90f60d
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMSparkMax.java
@@ -0,0 +1,44 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * REV Robotics SPARK MAX Motor Controller with PWM control.
+ *
+ * <p>Note that the SPARK MAX uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the SPARK MAX User Manual available from
+ * REV Robotics.
+ *
+ * <ul>
+ * <li>2.003ms = full "forward"
+ * <li>1.550ms = the "high end" of the deadband range
+ * <li>1.500ms = center of the deadband range (off)
+ * <li>1.460ms = the "low end" of the deadband range
+ * <li>0.999ms = full "reverse"
+ * </ul>
+ */
+public class PWMSparkMax extends PWMMotorController {
+ /**
+ * Common initialization code called by all constructors.
+ *
+ * @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port
+ */
+ public PWMSparkMax(final int channel) {
+ super("PWMSparkMax", channel);
+
+ m_pwm.setBounds(2.003, 1.55, 1.50, 1.46, 0.999);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_RevSparkMaxPWM, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMTalonFX.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMTalonFX.java
new file mode 100644
index 0000000..d521745
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMTalonFX.java
@@ -0,0 +1,45 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * Cross the Road Electronics (CTRE) Talon FX Motor Controller with PWM control.
+ *
+ * <p>Note that the TalonFX uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the TalonFX User Manual available from
+ * CTRE.
+ *
+ * <ul>
+ * <li>2.004ms = full "forward"
+ * <li>1.520ms = the "high end" of the deadband range
+ * <li>1.500ms = center of the deadband range (off)
+ * <li>1.480ms = the "low end" of the deadband range
+ * <li>0.997ms = full "reverse"
+ * </ul>
+ */
+public class PWMTalonFX extends PWMMotorController {
+ /**
+ * Constructor for a TalonFX connected via PWM.
+ *
+ * @param channel The PWM channel that the Talon FX is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public PWMTalonFX(final int channel) {
+ super("PWMTalonFX", channel);
+
+ m_pwm.setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_TalonFX, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMTalonSRX.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMTalonSRX.java
new file mode 100644
index 0000000..81f1834
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMTalonSRX.java
@@ -0,0 +1,45 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * Cross the Road Electronics (CTRE) Talon SRX Motor Controller with PWM control.
+ *
+ * <p>Note that the TalonSRX uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the TalonSRX User Manual available from
+ * CTRE.
+ *
+ * <ul>
+ * <li>2.004ms = full "forward"
+ * <li>1.520ms = the "high end" of the deadband range
+ * <li>1.500ms = center of the deadband range (off)
+ * <li>1.480ms = the "low end" of the deadband range
+ * <li>0.997ms = full "reverse"
+ * </ul>
+ */
+public class PWMTalonSRX extends PWMMotorController {
+ /**
+ * Constructor for a TalonSRX connected via PWM.
+ *
+ * @param channel The PWM channel that the Talon SRX is attached to. 0-9 are on-board, 10-19 are
+ * on the MXP port
+ */
+ public PWMTalonSRX(final int channel) {
+ super("PWMTalonSRX", channel);
+
+ m_pwm.setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_PWMTalonSRX, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMVenom.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMVenom.java
new file mode 100644
index 0000000..9f7a885
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMVenom.java
@@ -0,0 +1,44 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * Playing with Fusion Venom Smart Motor with PWM control.
+ *
+ * <p>Note that the Venom uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended.
+ *
+ * <ul>
+ * <li>2.004ms = full "forward"
+ * <li>1.520ms = the "high end" of the deadband range
+ * <li>1.500ms = center of the deadband range (off)
+ * <li>1.480ms = the "low end" of the deadband range
+ * <li>0.997ms = full "reverse"
+ * </ul>
+ */
+public class PWMVenom extends PWMMotorController {
+ /**
+ * Constructor for a Venom connected via PWM.
+ *
+ * @param channel The PWM channel that the Venom is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public PWMVenom(final int channel) {
+ super("PWMVenom", channel);
+
+ m_pwm.setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_FusionVenom, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMVictorSPX.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMVictorSPX.java
new file mode 100644
index 0000000..9880464
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/PWMVictorSPX.java
@@ -0,0 +1,45 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * Cross the Road Electronics (CTRE) Victor SPX Motor Controller with PWM control.
+ *
+ * <p>Note that the Victor SPX uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the Victor SPX User Manual available from
+ * CTRE.
+ *
+ * <ul>
+ * <li>2.004ms = full "forward"
+ * <li>1.520ms = the "high end" of the deadband range
+ * <li>1.500ms = center of the deadband range (off)
+ * <li>1.480ms = the "low end" of the deadband range
+ * <li>0.997ms = full "reverse"
+ * </ul>
+ */
+public class PWMVictorSPX extends PWMMotorController {
+ /**
+ * Constructor for a Victor SPX connected via PWM.
+ *
+ * @param channel The PWM channel that the PWMVictorSPX is attached to. 0-9 are on-board, 10-19
+ * are on the MXP port
+ */
+ public PWMVictorSPX(final int channel) {
+ super("PWMVictorSPX", channel);
+
+ m_pwm.setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_PWMVictorSPX, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/SD540.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/SD540.java
new file mode 100644
index 0000000..3876dfc
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/SD540.java
@@ -0,0 +1,45 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * Mindsensors SD540 Motor Controller.
+ *
+ * <p>Note that the SD540 uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the SD540 User Manual available from
+ * Mindsensors.
+ *
+ * <ul>
+ * <li>2.05ms = full "forward"
+ * <li>1.55ms = the "high end" of the deadband range
+ * <li>1.50ms = center of the deadband range (off)
+ * <li>1.44ms = the "low end" of the deadband range
+ * <li>0.94ms = full "reverse"
+ * </ul>
+ */
+public class SD540 extends PWMMotorController {
+ /**
+ * Constructor.
+ *
+ * @param channel The PWM channel that the SD540 is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public SD540(final int channel) {
+ super("SD540", channel);
+
+ m_pwm.setBounds(2.05, 1.55, 1.50, 1.44, 0.94);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_MindsensorsSD540, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Spark.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Spark.java
new file mode 100644
index 0000000..1b99228
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Spark.java
@@ -0,0 +1,45 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * REV Robotics SPARK Motor Controller.
+ *
+ * <p>Note that the SPARK uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the Spark User Manual available from REV
+ * Robotics.
+ *
+ * <ul>
+ * <li>2.003ms = full "forward"
+ * <li>1.550ms = the "high end" of the deadband range
+ * <li>1.500ms = center of the deadband range (off)
+ * <li>1.460ms = the "low end" of the deadband range
+ * <li>0.999ms = full "reverse"
+ * </ul>
+ */
+public class Spark extends PWMMotorController {
+ /**
+ * Constructor.
+ *
+ * @param channel The PWM channel that the SPARK is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public Spark(final int channel) {
+ super("Spark", channel);
+
+ m_pwm.setBounds(2.003, 1.55, 1.50, 1.46, 0.999);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_RevSPARK, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Talon.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Talon.java
new file mode 100644
index 0000000..576ba6a
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Talon.java
@@ -0,0 +1,44 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * Cross the Road Electronics (CTRE) Talon and Talon SR Motor Controller.
+ *
+ * <p>Note that the Talon uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the Talon User Manual available from CTRE.
+ *
+ * <ul>
+ * <li>2.037ms = full "forward"
+ * <li>1.539ms = the "high end" of the deadband range
+ * <li>1.513ms = center of the deadband range (off)
+ * <li>1.487ms = the "low end" of the deadband range
+ * <li>0.989ms = full "reverse"
+ * </ul>
+ */
+public class Talon extends PWMMotorController {
+ /**
+ * Constructor for a Talon (original or Talon SR).
+ *
+ * @param channel The PWM channel that the Talon is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public Talon(final int channel) {
+ super("Talon", channel);
+
+ m_pwm.setBounds(2.037, 1.539, 1.513, 1.487, 0.989);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_Talon, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Victor.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Victor.java
new file mode 100644
index 0000000..fac6c4f
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/Victor.java
@@ -0,0 +1,47 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * VEX Robotics Victor 888 Motor Controller The Vex Robotics Victor 884 Motor Controller can also be
+ * used with this class but may need to be calibrated per the Victor 884 user manual.
+ *
+ * <p>Note that the Victor uses the following bounds for PWM values. These values were determined
+ * empirically and optimized for the Victor 888. These values should work reasonably well for Victor
+ * 884 controllers also but if users experience issues such as asymmetric behavior around the
+ * deadband or inability to saturate the controller in either direction, calibration is recommended.
+ * The calibration procedure can be found in the Victor 884 User Manual available from VEX Robotics:
+ * http://content.vexrobotics.com/docs/ifi-v884-users-manual-9-25-06.pdf
+ *
+ * <ul>
+ * <li>2.027ms = full "forward"
+ * <li>1.525ms = the "high end" of the deadband range
+ * <li>1.507ms = center of the deadband range (off)
+ * <li>1.490ms = the "low end" of the deadband range
+ * <li>1.026ms = full "reverse"
+ * </ul>
+ */
+public class Victor extends PWMMotorController {
+ /**
+ * Constructor.
+ *
+ * @param channel The PWM channel that the Victor is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public Victor(final int channel) {
+ super("Victor", channel);
+
+ m_pwm.setBounds(2.027, 1.525, 1.507, 1.49, 1.026);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k2X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_Victor, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/VictorSP.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/VictorSP.java
new file mode 100644
index 0000000..10dba67
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/motorcontrol/VictorSP.java
@@ -0,0 +1,45 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import edu.wpi.first.hal.FRCNetComm.tResourceType;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+
+/**
+ * VEX Robotics Victor SP Motor Controller.
+ *
+ * <p>Note that the VictorSP uses the following bounds for PWM values. These values should work
+ * reasonably well for most controllers, but if users experience issues such as asymmetric behavior
+ * around the deadband or inability to saturate the controller in either direction, calibration is
+ * recommended. The calibration procedure can be found in the VictorSP User Manual available from
+ * CTRE.
+ *
+ * <ul>
+ * <li>2.004ms = full "forward"
+ * <li>1.520ms = the "high end" of the deadband range
+ * <li>1.500ms = center of the deadband range (off)
+ * <li>1.480ms = the "low end" of the deadband range
+ * <li>0.997ms = full "reverse"
+ * </ul>
+ */
+public class VictorSP extends PWMMotorController {
+ /**
+ * Constructor.
+ *
+ * @param channel The PWM channel that the VictorSP is attached to. 0-9 are on-board, 10-19 are on
+ * the MXP port
+ */
+ public VictorSP(final int channel) {
+ super("VictorSP", channel);
+
+ m_pwm.setBounds(2.004, 1.52, 1.50, 1.48, 0.997);
+ m_pwm.setPeriodMultiplier(PWM.PeriodMultiplier.k1X);
+ m_pwm.setSpeed(0.0);
+ m_pwm.setZeroLatch();
+
+ HAL.report(tResourceType.kResourceType_VictorSP, getChannel() + 1);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/BuiltInLayouts.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/BuiltInLayouts.java
index 27c3e8c..fb642ae 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/BuiltInLayouts.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/BuiltInLayouts.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
@@ -18,8 +15,9 @@
public enum BuiltInLayouts implements LayoutType {
/**
* Groups components in a vertical list. New widgets added to the layout will be placed at the
- * bottom of the list.
- * <br>Custom properties:
+ * bottom of the list. <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Label position</td><td>String</td><td>"BOTTOM"</td>
@@ -30,8 +28,9 @@
kList("List Layout"),
/**
- * Groups components in an <i>n</i> x <i>m</i> grid. Grid layouts default to 3x3.
- * <br>Custom properties:
+ * Groups components in an <i>n</i> x <i>m</i> grid. Grid layouts default to 3x3. <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Number of columns</td><td>Number</td><td>3</td><td>Must be in the range [1,15]</td>
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/BuiltInWidgets.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/BuiltInWidgets.java
index fa98a0e..82f2745 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/BuiltInWidgets.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/BuiltInWidgets.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
@@ -13,6 +10,7 @@
* The types of the widgets bundled with Shuffleboard.
*
* <p>For example, setting a number to be displayed with a slider:
+ *
* <pre>{@code
* NetworkTableEntry example = Shuffleboard.getTab("My Tab")
* .add("My Number", 0)
@@ -26,23 +24,30 @@
*/
public enum BuiltInWidgets implements WidgetType {
/**
- * Displays a value with a simple text field.
- * <br>Supported types:
+ * Displays a value with a simple text field. <br>
+ * Supported types:
+ *
* <ul>
- * <li>String</li>
- * <li>Number</li>
- * <li>Boolean</li>
+ * <li>String
+ * <li>Number
+ * <li>Boolean
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kTextView("Text View"),
/**
- * Displays a number with a controllable slider.
- * <br>Supported types:
+ * Displays a number with a controllable slider. <br>
+ * Supported types:
+ *
* <ul>
- * <li>Number</li>
+ * <li>Number
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Min</td><td>Number</td><td>-1.0</td><td>The minimum value of the slider</td></tr>
@@ -53,12 +58,16 @@
*/
kNumberSlider("Number Slider"),
/**
- * Displays a number with a view-only bar.
- * <br>Supported types:
+ * Displays a number with a view-only bar. <br>
+ * Supported types:
+ *
* <ul>
- * <li>Number</li>
+ * <li>Number
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Min</td><td>Number</td><td>-1.0</td><td>The minimum value of the bar</td></tr>
@@ -69,11 +78,16 @@
kNumberBar("Number Bar"),
/**
* Displays a number with a view-only dial. Displayed values are rounded to the nearest integer.
- * <br>Supported types:
+ * <br>
+ * Supported types:
+ *
* <ul>
- * <li>Number</li>
+ * <li>Number
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Min</td><td>Number</td><td>0</td><td>The minimum value of the dial</td></tr>
@@ -86,13 +100,17 @@
/**
* Displays a number with a graph. <strong>NOTE:</strong> graphs can be taxing on the computer
* running the dashboard. Keep the number of visible data points to a minimum. Making the widget
- * smaller also helps with performance, but may cause the graph to become difficult to read.
- * <br>Supported types:
+ * smaller also helps with performance, but may cause the graph to become difficult to read. <br>
+ * Supported types:
+ *
* <ul>
- * <li>Number</li>
- * <li>Number array</li>
+ * <li>Number
+ * <li>Number array
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Visible time</td><td>Number</td><td>30</td>
@@ -101,12 +119,16 @@
*/
kGraph("Graph"),
/**
- * Displays a boolean value as a large colored box.
- * <br>Supported types:
+ * Displays a boolean value as a large colored box. <br>
+ * Supported types:
+ *
* <ul>
- * <li>Boolean</li>
+ * <li>Boolean
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Color when true</td><td>Color</td><td>"green"</td>
@@ -118,31 +140,41 @@
*/
kBooleanBox("Boolean Box"),
/**
- * Displays a boolean with a large interactive toggle button.
- * <br>Supported types:
+ * Displays a boolean with a large interactive toggle button. <br>
+ * Supported types:
+ *
* <ul>
- * <li>Boolean</li>
+ * <li>Boolean
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kToggleButton("Toggle Button"),
/**
- * Displays a boolean with a fixed-size toggle switch.
- * <br>Supported types:
+ * Displays a boolean with a fixed-size toggle switch. <br>
+ * Supported types:
+ *
* <ul>
- * <li>Boolean</li>
+ * <li>Boolean
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kToggleSwitch("Toggle Switch"),
/**
- * Displays an analog input or a raw number with a number bar.
- * <br>Supported types:
+ * Displays an analog input or a raw number with a number bar. <br>
+ * Supported types:
+ *
* <ul>
- * <li>Number</li>
- * <li>{@link edu.wpi.first.wpilibj.AnalogInput}</li>
+ * <li>Number
+ * <li>{@link edu.wpi.first.wpilibj.AnalogInput}
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Min</td><td>Number</td><td>0</td><td>The minimum value of the bar</td></tr>
@@ -156,121 +188,151 @@
*/
kVoltageView("Voltage View"),
/**
- * Displays a {@link edu.wpi.first.wpilibj.PowerDistributionPanel PowerDistributionPanel}.
- * <br>Supported types:
+ * Displays a {@link edu.wpi.first.wpilibj.PowerDistribution PowerDistribution}. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.PowerDistributionPanel}</li>
+ * <li>{@link edu.wpi.first.wpilibj.PowerDistribution}
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Show voltage and current values</td><td>Boolean</td><td>true</td>
* <td>Whether or not to display the voltage and current draw</td></tr>
* </table>
*/
- kPowerDistributionPanel("PDP"),
+ kPowerDistribution("PDP"),
/**
- * Displays a {@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser SendableChooser} with
- * a dropdown combo box with a list of options.
- * <br>Supported types:
+ * Displays a {@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser SendableChooser} with a
+ * dropdown combo box with a list of options. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser}</li>
+ * <li>{@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser}
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kComboBoxChooser("ComboBox Chooser"),
/**
- * Displays a {@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser SendableChooser} with
- * a toggle button for each available option.
- * <br>Supported types:
+ * Displays a {@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser SendableChooser} with a
+ * toggle button for each available option. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser}</li>
+ * <li>{@link edu.wpi.first.wpilibj.smartdashboard.SendableChooser}
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kSplitButtonChooser("Split Button Chooser"),
/**
* Displays an {@link edu.wpi.first.wpilibj.Encoder} displaying its speed, total traveled
- * distance, and its distance per tick.
- * <br>Supported types:
+ * distance, and its distance per tick. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.Encoder}</li>
+ * <li>{@link edu.wpi.first.wpilibj.Encoder}
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kEncoder("Encoder"),
/**
- * Displays a {@link edu.wpi.first.wpilibj.SpeedController SpeedController}. The speed controller
- * will be controllable from the dashboard when test mode is enabled, but will otherwise be
- * view-only.
- * <br>Supported types:
+ * Displays a {@link edu.wpi.first.wpilibj.motorcontrol.MotorController MotorController}. The
+ * motor controller will be controllable from the dashboard when test mode is enabled, but will
+ * otherwise be view-only. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.PWMSpeedController}</li>
- * <li>{@link edu.wpi.first.wpilibj.DMC60}</li>
- * <li>{@link edu.wpi.first.wpilibj.Jaguar}</li>
- * <li>{@link edu.wpi.first.wpilibj.PWMSparkMax}</li>
- * <li>{@link edu.wpi.first.wpilibj.PWMTalonFX}</li>
- * <li>{@link edu.wpi.first.wpilibj.PWMTalonSRX}</li>
- * <li>{@link edu.wpi.first.wpilibj.PWMVenom}</li>
- * <li>{@link edu.wpi.first.wpilibj.PWMVictorSPX}</li>
- * <li>{@link edu.wpi.first.wpilibj.SD540}</li>
- * <li>{@link edu.wpi.first.wpilibj.Spark}</li>
- * <li>{@link edu.wpi.first.wpilibj.Talon}</li>
- * <li>{@link edu.wpi.first.wpilibj.Victor}</li>
- * <li>{@link edu.wpi.first.wpilibj.VictorSP}</li>
- * <li>{@link edu.wpi.first.wpilibj.SpeedControllerGroup}</li>
- * <li>Any custom subclass of {@code SpeedController}</li>
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.PWMMotorController}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.DMC60}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.Jaguar}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.PWMSparkMax}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.PWMTalonFX}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.PWMTalonSRX}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.PWMVenom}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.PWMVictorSPX}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.SD540}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.Spark}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.Talon}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.Victor}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.VictorSP}
+ * <li>{@link edu.wpi.first.wpilibj.motorcontrol.MotorControllerGroup}
+ * <li>Any custom subclass of {@code MotorController}
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Orientation</td><td>String</td><td>"HORIZONTAL"</td>
* <td>One of {@code ["HORIZONTAL", "VERTICAL"]}</td></tr>
* </table>
*/
- kSpeedController("Speed Controller"),
+ kMotorController("Motor Controller"),
/**
* Displays a command with a toggle button. Pressing the button will start the command, and the
- * button will automatically release when the command completes.
- * <br>Supported types:
+ * button will automatically release when the command completes. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.command.Command}</li>
- * <li>{@link edu.wpi.first.wpilibj.command.CommandGroup}</li>
- * <li>Any custom subclass of {@code Command} or {@code CommandGroup}</li>
+ * <li>{@link edu.wpi.first.wpilibj.command.Command}
+ * <li>{@link edu.wpi.first.wpilibj.command.CommandGroup}
+ * <li>Any custom subclass of {@code Command} or {@code CommandGroup}
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kCommand("Command"),
/**
* Displays a PID command with a checkbox and an editor for the PIDF constants. Selecting the
* checkbox will start the command, and the checkbox will automatically deselect when the command
- * completes.
- * <br>Supported types:
+ * completes. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.command.PIDCommand}</li>
- * <li>Any custom subclass of {@code PIDCommand}</li>
+ * <li>{@link edu.wpi.first.wpilibj.command.PIDCommand}
+ * <li>Any custom subclass of {@code PIDCommand}
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kPIDCommand("PID Command"),
/**
* Displays a PID controller with an editor for the PIDF constants and a toggle switch for
- * enabling and disabling the controller.
- * <br>Supported types:
+ * enabling and disabling the controller. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.PIDController}</li>
+ * <li>{@link edu.wpi.first.wpilibj.PIDController}
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kPIDController("PID Controller"),
/**
* Displays an accelerometer with a number bar displaying the magnitude of the acceleration and
- * text displaying the exact value.
- * <br>Supported types:
+ * text displaying the exact value. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.AnalogAccelerometer}</li>
+ * <li>{@link edu.wpi.first.wpilibj.AnalogAccelerometer}
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Min</td><td>Number</td><td>-1</td>
@@ -287,14 +349,18 @@
*/
kAccelerometer("Accelerometer"),
/**
- * Displays a 3-axis accelerometer with a number bar for each axis' acceleration.
- * <br>Supported types:
+ * Displays a 3-axis accelerometer with a number bar for each axis' acceleration. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.ADXL345_I2C}</li>
- * <li>{@link edu.wpi.first.wpilibj.ADXL345_SPI}</li>
- * <li>{@link edu.wpi.first.wpilibj.ADXL362}</li>
+ * <li>{@link edu.wpi.first.wpilibj.ADXL345_I2C}
+ * <li>{@link edu.wpi.first.wpilibj.ADXL345_SPI}
+ * <li>{@link edu.wpi.first.wpilibj.ADXL362}
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Range</td><td>{@link Range}</td><td>k16G</td><td>The accelerometer range</td></tr>
@@ -308,14 +374,18 @@
*/
k3AxisAccelerometer("3-Axis Accelerometer"),
/**
- * Displays a gyro with a dial from 0 to 360 degrees.
- * <br>Supported types:
+ * Displays a gyro with a dial from 0 to 360 degrees. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.ADXRS450_Gyro}</li>
- * <li>{@link edu.wpi.first.wpilibj.AnalogGyro}</li>
- * <li>Any custom subclass of {@code GyroBase} (such as a MXP gyro)</li>
+ * <li>{@link edu.wpi.first.wpilibj.ADXRS450_Gyro}
+ * <li>{@link edu.wpi.first.wpilibj.AnalogGyro}
+ * <li>Any custom subclass of {@code GyroBase} (such as a MXP gyro)
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Major tick spacing</td><td>Number</td><td>45</td><td>Degrees</td></tr>
@@ -326,23 +396,30 @@
*/
kGyro("Gyro"),
/**
- * Displays a relay with toggle buttons for each supported mode (off, on, forward, reverse).
- * <br>Supported types:
+ * Displays a relay with toggle buttons for each supported mode (off, on, forward, reverse). <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.Relay}</li>
+ * <li>{@link edu.wpi.first.wpilibj.Relay}
* </ul>
- * <br>This widget has no custom properties.
+ *
+ * <br>
+ * This widget has no custom properties.
*/
kRelay("Relay"),
/**
* Displays a differential drive with a widget that displays the speed of each side of the
* drivebase and a vector for the direction and rotation of the drivebase. The widget will be
- * controllable if the robot is in test mode.
- * <br>Supported types:
+ * controllable if the robot is in test mode. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.drive.DifferentialDrive}</li>
+ * <li>{@link edu.wpi.first.wpilibj.drive.DifferentialDrive}
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Number of wheels</td><td>Number</td><td>4</td><td>Must be a positive even integer
@@ -354,13 +431,17 @@
kDifferentialDrive("Differential Drivebase"),
/**
* Displays a mecanum drive with a widget that displays the speed of each wheel, and vectors for
- * the direction and rotation of the drivebase. The widget will be controllable if the robot is
- * in test mode.
- * <br>Supported types:
+ * the direction and rotation of the drivebase. The widget will be controllable if the robot is in
+ * test mode. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.first.wpilibj.drive.MecanumDrive}</li>
+ * <li>{@link edu.wpi.first.wpilibj.drive.MecanumDrive}
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Show velocity vectors</td><td>Boolean</td><td>true</td></tr>
@@ -368,12 +449,16 @@
*/
kMecanumDrive("Mecanum Drivebase"),
/**
- * Displays a camera stream.
- * <br>Supported types:
+ * Displays a camera stream. <br>
+ * Supported types:
+ *
* <ul>
- * <li>{@link edu.wpi.cscore.VideoSource} (as long as it is streaming on an MJPEG server)</li>
+ * <li>{@link edu.wpi.first.cscore.VideoSource} (as long as it is streaming on an MJPEG server)
* </ul>
- * <br>Custom properties:
+ *
+ * <br>
+ * Custom properties:
+ *
* <table>
* <tr><th>Name</th><th>Type</th><th>Default Value</th><th>Notes</th></tr>
* <tr><td>Show crosshair</td><td>Boolean</td><td>true</td>
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ComplexWidget.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ComplexWidget.java
index d56fde8..cef9c07 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ComplexWidget.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ComplexWidget.java
@@ -1,19 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
import edu.wpi.first.networktables.NetworkTable;
-import edu.wpi.first.wpilibj.Sendable;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
+import edu.wpi.first.util.sendable.Sendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilderImpl;
/**
- * A Shuffleboard widget that handles a {@link Sendable} object such as a speed controller or
+ * A Shuffleboard widget that handles a {@link Sendable} object such as a motor controller or
* sensor.
*/
public final class ComplexWidget extends ShuffleboardWidget<ComplexWidget> {
@@ -34,7 +30,7 @@
m_sendable.initSendable(m_builder);
m_builder.startListeners();
}
- m_builder.updateTable();
+ m_builder.update();
}
/**
@@ -58,5 +54,4 @@
m_builder.stopLiveWindowMode();
}
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ContainerHelper.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ContainerHelper.java
index 26649d0..58ac678 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ContainerHelper.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ContainerHelper.java
@@ -1,12 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableRegistry;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -20,13 +20,7 @@
import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
-import edu.wpi.first.networktables.NetworkTableEntry;
-import edu.wpi.first.wpilibj.Sendable;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * A helper class for Shuffleboard containers to handle common child operations.
- */
+/** A helper class for Shuffleboard containers to handle common child operations. */
final class ContainerHelper {
private final ShuffleboardContainer m_container;
private final Set<String> m_usedTitles = new HashSet<>();
@@ -126,9 +120,8 @@
checkTitle(title);
}
- private <T> SuppliedValueWidget<T> addSupplied(String title,
- Supplier<T> supplier,
- BiConsumer<NetworkTableEntry, T> setter) {
+ private <T> SuppliedValueWidget<T> addSupplied(
+ String title, Supplier<T> supplier, BiConsumer<NetworkTableEntry, T> setter) {
SuppliedValueWidget<T> widget = new SuppliedValueWidget<>(m_container, title, supplier, setter);
m_components.add(widget);
return widget;
@@ -147,5 +140,4 @@
}
m_usedTitles.add(title);
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/EventImportance.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/EventImportance.java
index 08f9712..4d64efe 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/EventImportance.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/EventImportance.java
@@ -1,16 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
/**
- * The importance of an event marker in Shuffleboard. The exact meaning of each importance level is
- * up for interpretation on a team-to-team basis, but users should follow the general guidelines
- * of the various importance levels. The examples given are for reference and may be ignored or
+ * The importance of an event marker in Shuffleboard. The exact meaning of each importance level is
+ * up for interpretation on a team-to-team basis, but users should follow the general guidelines of
+ * the various importance levels. The examples given are for reference and may be ignored or
* considered to be more or less important from team to team.
*/
public enum EventImportance {
@@ -18,14 +15,10 @@
// Modifying the enum or enum strings requires a corresponding change to the C++ enum
// and the enum in Shuffleboard
- /**
- * A trivial event such as a change in command state.
- */
+ /** A trivial event such as a change in command state. */
kTrivial("TRIVIAL"),
- /**
- * A low importance event such as acquisition of a game piece.
- */
+ /** A low importance event such as acquisition of a game piece. */
kLow("LOW"),
/**
@@ -33,14 +26,10 @@
*/
kNormal("NORMAL"),
- /**
- * A high-importance event such as scoring a game piece.
- */
+ /** A high-importance event such as scoring a game piece. */
kHigh("HIGH"),
- /**
- * A critically important event such as a brownout, component failure, or software deadlock.
- */
+ /** A critically important event such as a brownout, component failure, or software deadlock. */
kCritical("CRITICAL");
private final String m_simpleName;
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/LayoutType.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/LayoutType.java
index 2d7b565..82ffcbe 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/LayoutType.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/LayoutType.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
@@ -16,6 +13,8 @@
public interface LayoutType {
/**
* Gets the string type of the layout as defined by that layout in Shuffleboard.
+ *
+ * @return The string type of the layout.
*/
String getLayoutName();
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/RecordingController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/RecordingController.java
index 9f04274..a7be3c9 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/RecordingController.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/RecordingController.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
@@ -12,9 +9,7 @@
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.DriverStation;
-/**
- * Controls Shuffleboard recordings via NetworkTables.
- */
+/** Controls Shuffleboard recordings via NetworkTables. */
final class RecordingController {
private static final String kRecordingTableName = "/Shuffleboard/.recording/";
private static final String kRecordingControlKey = kRecordingTableName + "RecordData";
@@ -49,21 +44,20 @@
public void addEventMarker(String name, String description, EventImportance importance) {
if (name == null || name.isEmpty()) {
- DriverStation.reportError(
- "Shuffleboard event name was not specified", true);
+ DriverStation.reportError("Shuffleboard event name was not specified", true);
return;
}
if (importance == null) {
- DriverStation.reportError(
- "Shuffleboard event importance was null", true);
+ DriverStation.reportError("Shuffleboard event importance was null", true);
return;
}
String eventDescription = description == null ? "" : description;
- m_eventsTable.getSubTable(name)
+ m_eventsTable
+ .getSubTable(name)
.getEntry("Info")
- .setStringArray(new String[]{eventDescription, importance.getSimpleName()});
+ .setStringArray(new String[] {eventDescription, importance.getSimpleName()});
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SendableCameraWrapper.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SendableCameraWrapper.java
index bb7738f..ee72303 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SendableCameraWrapper.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SendableCameraWrapper.java
@@ -1,23 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
+import edu.wpi.first.cscore.VideoSource;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
import java.util.Map;
import java.util.WeakHashMap;
-import edu.wpi.cscore.VideoSource;
-import edu.wpi.first.wpilibj.Sendable;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
-
-/**
- * A wrapper to make video sources sendable and usable from Shuffleboard.
- */
+/** A wrapper to make video sources sendable and usable from Shuffleboard. */
public final class SendableCameraWrapper implements Sendable, AutoCloseable {
private static final String kProtocol = "camera_server://";
@@ -26,8 +20,8 @@
private final String m_uri;
/**
- * Creates a new sendable wrapper. Private constructor to avoid direct instantiation with
- * multiple wrappers floating around for the same camera.
+ * Creates a new sendable wrapper. Private constructor to avoid direct instantiation with multiple
+ * wrappers floating around for the same camera.
*
* @param source the source to wrap
*/
@@ -43,12 +37,12 @@
}
/**
- * Gets a sendable wrapper object for the given video source, creating the wrapper if one does
- * not already exist for the source.
+ * Gets a sendable wrapper object for the given video source, creating the wrapper if one does not
+ * already exist for the source.
*
* @param source the video source to wrap
- * @return a sendable wrapper object for the video source, usable in Shuffleboard via
- * {@link ShuffleboardTab#add(Sendable)} and {@link ShuffleboardLayout#add(Sendable)}
+ * @return a sendable wrapper object for the video source, usable in Shuffleboard via {@link
+ * ShuffleboardTab#add(Sendable)} and {@link ShuffleboardLayout#add(Sendable)}
*/
public static SendableCameraWrapper wrap(VideoSource source) {
return m_wrappers.computeIfAbsent(source, SendableCameraWrapper::new);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/Shuffleboard.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/Shuffleboard.java
index c88256a..1bea28e 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/Shuffleboard.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/Shuffleboard.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
@@ -16,7 +13,8 @@
* example, programmers can specify a specific {@code boolean} value to be displayed with a toggle
* button instead of the default colored box, or set custom colors for that box.
*
- * <p>For example, displaying a boolean entry with a toggle button:</p>
+ * <p>For example, displaying a boolean entry with a toggle button:
+ *
* <pre>{@code
* NetworkTableEntry myBoolean = Shuffleboard.getTab("Example Tab")
* .add("My Boolean", false)
@@ -24,7 +22,8 @@
* .getEntry();
* }</pre>
*
- * <p>Changing the colors of the boolean box:</p>
+ * <p>Changing the colors of the boolean box:
+ *
* <pre>{@code
* NetworkTableEntry myBoolean = Shuffleboard.getTab("Example Tab")
* .add("My Boolean", false)
@@ -34,7 +33,8 @@
* }</pre>
*
* <p>Specifying a parent layout. Note that the layout type must <i>always</i> be specified, even if
- * the layout has already been generated by a previously defined entry.</p>
+ * the layout has already been generated by a previously defined entry.
+ *
* <pre>{@code
* NetworkTableEntry myBoolean = Shuffleboard.getTab("Example Tab")
* .getLayout("List", "Example List")
@@ -43,12 +43,10 @@
* .getEntry();
* }</pre>
*
- * <p>Teams are encouraged to set up shuffleboard layouts at the start of the robot program.</p>
+ * <p>Teams are encouraged to set up shuffleboard layouts at the start of the robot program.
*/
public final class Shuffleboard {
- /**
- * The name of the base NetworkTable into which all Shuffleboard data will be added.
- */
+ /** The name of the base NetworkTable into which all Shuffleboard data will be added. */
public static final String kBaseTableName = "/Shuffleboard";
private static final ShuffleboardRoot root =
@@ -80,8 +78,8 @@
}
/**
- * Selects the tab in the dashboard with the given index in the range [0..n-1], where <i>n</i>
- * is the number of tabs in the dashboard at the time this method is called.
+ * Selects the tab in the dashboard with the given index in the range [0..n-1], where <i>n</i> is
+ * the number of tabs in the dashboard at the time this method is called.
*
* @param index the index of the tab to select
*/
@@ -99,10 +97,10 @@
}
/**
- * Enables user control of widgets containing actuators: speed controllers, relays, etc. This
- * should only be used when the robot is in test mode. IterativeRobotBase and SampleRobot are
- * both configured to call this method when entering test mode; most users should not need to use
- * this method directly.
+ * Enables user control of widgets containing actuators: motor controllers, relays, etc. This
+ * should only be used when the robot is in test mode. IterativeRobotBase and SampleRobot are both
+ * configured to call this method when entering test mode; most users should not need to use this
+ * method directly.
*/
public static void enableActuatorWidgets() {
root.enableActuatorWidgets();
@@ -111,8 +109,8 @@
/**
* Disables user control of widgets containing actuators. For safety reasons, actuators should
* only be controlled while in test mode. IterativeRobotBase and SampleRobot are both configured
- * to call this method when exiting in test mode; most users should not need to use
- * this method directly.
+ * to call this method when exiting in test mode; most users should not need to use this method
+ * directly.
*/
public static void disableActuatorWidgets() {
update(); // Need to update to make sure the sendable builders are initialized
@@ -143,11 +141,10 @@
*
* <p>To avoid recording files overwriting each other, make sure to use unique recording file
* names. File name formats accept templates for inserting the date and time when the recording
- * started with the {@code ${date}} and {@code ${time}} templates, respectively. For example,
- * the default format is {@code "recording-${time}"} and recording files created with it will have
+ * started with the {@code ${date}} and {@code ${time}} templates, respectively. For example, the
+ * default format is {@code "recording-${time}"} and recording files created with it will have
* names like {@code "recording-2018.01.15.sbr"}. Users are <strong>strongly</strong> recommended
* to use the {@code ${time}} template to ensure unique file names.
- * </p>
*
* @param format the format for the
* @see #clearRecordingFileNameFormat()
@@ -170,12 +167,12 @@
* state to as critical as a total power loss or component failure. If Shuffleboard is recording,
* the event will also be recorded.
*
- * <p>If {@code name} is {@code null} or empty, or {@code importance} is {@code null}, then
- * no event will be sent and an error will be printed to the driver station.
+ * <p>If {@code name} is {@code null} or empty, or {@code importance} is {@code null}, then no
+ * event will be sent and an error will be printed to the driver station.
*
- * @param name the name of the event
+ * @param name the name of the event
* @param description a description of the event
- * @param importance the importance of the event
+ * @param importance the importance of the event
*/
public static void addEventMarker(String name, String description, EventImportance importance) {
recordingController.addEventMarker(name, description, importance);
@@ -186,11 +183,11 @@
* state to as critical as a total power loss or component failure. If Shuffleboard is recording,
* the event will also be recorded.
*
- * <p>If {@code name} is {@code null} or empty, or {@code importance} is {@code null}, then
- * no event will be sent and an error will be printed to the driver station.
+ * <p>If {@code name} is {@code null} or empty, or {@code importance} is {@code null}, then no
+ * event will be sent and an error will be printed to the driver station.
*
- * @param name the name of the event
- * @param importance the importance of the event
+ * @param name the name of the event
+ * @param importance the importance of the event
*/
public static void addEventMarker(String name, EventImportance importance) {
addEventMarker(name, "", importance);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardComponent.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardComponent.java
index 5d90396..fd7d541 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardComponent.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardComponent.java
@@ -1,17 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
-import java.util.Map;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.networktables.NetworkTable;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import java.util.Map;
/**
* A generic component in Shuffleboard.
@@ -58,9 +54,7 @@
return m_title;
}
- /**
- * Gets the custom properties for this component. May be null.
- */
+ /** Gets the custom properties for this component. May be null. */
final Map<String, Object> getProperties() {
return m_properties;
}
@@ -72,6 +66,7 @@
* @param properties the properties for this component
* @return this component
*/
+ @SuppressWarnings("unchecked")
public final C withProperties(Map<String, Object> properties) {
m_properties = properties;
m_metadataDirty = true;
@@ -87,9 +82,10 @@
* component there before the one with the specific position is sent.
*
* @param columnIndex the column in the tab to place this component
- * @param rowIndex the row in the tab to place this component
+ * @param rowIndex the row in the tab to place this component
* @return this component
*/
+ @SuppressWarnings("unchecked")
public final C withPosition(int columnIndex, int rowIndex) {
m_column = columnIndex;
m_row = rowIndex;
@@ -101,10 +97,11 @@
* Sets the size of this component in the tab. This has no effect if this component is inside a
* layout.
*
- * @param width how many columns wide the component should be
+ * @param width how many columns wide the component should be
* @param height how many rows high the component should be
* @return this component
*/
+ @SuppressWarnings("unchecked")
public final C withSize(int width, int height) {
m_width = width;
m_height = height;
@@ -127,14 +124,14 @@
if (m_width <= 0 || m_height <= 0) {
metaTable.getEntry("Size").delete();
} else {
- metaTable.getEntry("Size").setDoubleArray(new double[]{m_width, m_height});
+ metaTable.getEntry("Size").setDoubleArray(new double[] {m_width, m_height});
}
// Tile position
if (m_column < 0 || m_row < 0) {
metaTable.getEntry("Position").delete();
} else {
- metaTable.getEntry("Position").setDoubleArray(new double[]{m_column, m_row});
+ metaTable.getEntry("Position").setDoubleArray(new double[] {m_column, m_row});
}
// Custom properties
@@ -144,5 +141,4 @@
}
m_metadataDirty = false;
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardContainer.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardContainer.java
index 9a89404..8b4e009 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardContainer.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardContainer.java
@@ -1,39 +1,34 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
+import edu.wpi.first.cscore.VideoSource;
+import edu.wpi.first.util.sendable.Sendable;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.BooleanSupplier;
import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
-import edu.wpi.cscore.VideoSource;
-import edu.wpi.first.wpilibj.Sendable;
-
-/**
- * Common interface for objects that can contain shuffleboard components.
- */
+/** Common interface for objects that can contain shuffleboard components. */
public interface ShuffleboardContainer extends ShuffleboardValue {
-
/**
* Gets the components that are direct children of this container.
+ *
+ * @return The components that are direct children of this container.
*/
List<ShuffleboardComponent<?>> getComponents();
/**
* Gets the layout with the given type and title, creating it if it does not already exist at the
- * time this method is called. Note: this method should only be used to use a layout type that
- * is not already built into Shuffleboard. To use a layout built into Shuffleboard, use
- * {@link #getLayout(String, LayoutType)} and the layouts in {@link BuiltInLayouts}.
+ * time this method is called. Note: this method should only be used to use a layout type that is
+ * not already built into Shuffleboard. To use a layout built into Shuffleboard, use {@link
+ * #getLayout(String, LayoutType)} and the layouts in {@link BuiltInLayouts}.
*
* @param title the title of the layout
- * @param type the type of the layout, eg "List Layout" or "Grid Layout"
+ * @param type the type of the layout, eg "List Layout" or "Grid Layout"
* @return the layout
* @see #getLayout(String, LayoutType)
*/
@@ -43,7 +38,7 @@
* Gets the layout with the given type and title, creating it if it does not already exist at the
* time this method is called.
*
- * @param title the title of the layout
+ * @param title the title of the layout
* @param layoutType the type of the layout, eg "List" or "Grid"
* @return the layout
*/
@@ -72,11 +67,11 @@
/**
* Adds a widget to this container to display the given sendable.
*
- * @param title the title of the widget
+ * @param title the title of the widget
* @param sendable the sendable to display
* @return a widget to display the sendable data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
ComplexWidget add(String title, Sendable sendable) throws IllegalArgumentException;
@@ -87,7 +82,7 @@
* @param video the video stream to display
* @return a widget to display the sendable data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
default ComplexWidget add(String title, VideoSource video) throws IllegalArgumentException {
return add(title, SendableCameraWrapper.wrap(video));
@@ -99,7 +94,7 @@
* @param sendable the sendable to display
* @return a widget to display the sendable data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title, or if the sendable's name has not been specified
+ * title, or if the sendable's name has not been specified
*/
ComplexWidget add(Sendable sendable);
@@ -109,7 +104,7 @@
* @param video the video to display
* @return a widget to display the sendable data
* @throws IllegalArgumentException if a widget already exists in this container with the same
- * title as the video source
+ * title as the video source
*/
default ComplexWidget add(VideoSource video) {
return add(SendableCameraWrapper.wrap(video));
@@ -118,11 +113,11 @@
/**
* Adds a widget to this container to display the given data.
*
- * @param title the title of the widget
+ * @param title the title of the widget
* @param defaultValue the default value of the widget
* @return a widget to display the sendable data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
* @see #addPersistent(String, Object) add(String title, Object defaultValue)
*/
SimpleWidget add(String title, Object defaultValue) throws IllegalArgumentException;
@@ -136,7 +131,7 @@
* @param valueSupplier the supplier for values
* @return a widget to display data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
SuppliedValueWidget<String> addString(String title, Supplier<String> valueSupplier)
throws IllegalArgumentException;
@@ -150,7 +145,7 @@
* @param valueSupplier the supplier for values
* @return a widget to display data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
SuppliedValueWidget<Double> addNumber(String title, DoubleSupplier valueSupplier)
throws IllegalArgumentException;
@@ -164,7 +159,7 @@
* @param valueSupplier the supplier for values
* @return a widget to display data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
SuppliedValueWidget<Boolean> addBoolean(String title, BooleanSupplier valueSupplier)
throws IllegalArgumentException;
@@ -178,7 +173,7 @@
* @param valueSupplier the supplier for values
* @return a widget to display data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
SuppliedValueWidget<String[]> addStringArray(String title, Supplier<String[]> valueSupplier)
throws IllegalArgumentException;
@@ -192,7 +187,7 @@
* @param valueSupplier the supplier for values
* @return a widget to display data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
SuppliedValueWidget<double[]> addDoubleArray(String title, Supplier<double[]> valueSupplier)
throws IllegalArgumentException;
@@ -206,7 +201,7 @@
* @param valueSupplier the supplier for values
* @return a widget to display data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
SuppliedValueWidget<boolean[]> addBooleanArray(String title, Supplier<boolean[]> valueSupplier)
throws IllegalArgumentException;
@@ -220,21 +215,21 @@
* @param valueSupplier the supplier for values
* @return a widget to display data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
*/
SuppliedValueWidget<byte[]> addRaw(String title, Supplier<byte[]> valueSupplier)
throws IllegalArgumentException;
/**
- * Adds a widget to this container to display a simple piece of data. Unlike
- * {@link #add(String, Object)}, the value in the widget will be saved on the robot and will be
- * used when the robot program next starts rather than {@code defaultValue}.
+ * Adds a widget to this container to display a simple piece of data. Unlike {@link #add(String,
+ * Object)}, the value in the widget will be saved on the robot and will be used when the robot
+ * program next starts rather than {@code defaultValue}.
*
- * @param title the title of the widget
+ * @param title the title of the widget
* @param defaultValue the default value of the widget
* @return a widget to display the sendable data
* @throws IllegalArgumentException if a widget already exists in this container with the given
- * title
+ * title
* @see #add(String, Object) add(String title, Object defaultValue)
*/
default SimpleWidget addPersistent(String title, Object defaultValue)
@@ -243,5 +238,4 @@
widget.getEntry().setPersistent();
return widget;
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstance.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstance.java
index 8af1d78..a864433 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstance.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstance.java
@@ -1,23 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.function.Consumer;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Consumer;
final class ShuffleboardInstance implements ShuffleboardRoot {
private final Map<String, ShuffleboardTab> m_tabs = new LinkedHashMap<>();
@@ -53,10 +49,8 @@
@Override
public void update() {
if (m_tabsChanged) {
- String[] tabTitles = m_tabs.values()
- .stream()
- .map(ShuffleboardTab::getTitle)
- .toArray(String[]::new);
+ String[] tabTitles =
+ m_tabs.values().stream().map(ShuffleboardTab::getTitle).toArray(String[]::new);
m_rootMetaTable.getEntry("Tabs").forceSetStringArray(tabTitles);
m_tabsChanged = false;
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardLayout.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardLayout.java
index b6ed776..726f9cc 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardLayout.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardLayout.java
@@ -1,26 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.util.sendable.Sendable;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.BooleanSupplier;
import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
-import edu.wpi.first.networktables.NetworkTable;
-import edu.wpi.first.wpilibj.Sendable;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
-
-/**
- * A layout in a Shuffleboard tab. Layouts can contain widgets and other layouts.
- */
+/** A layout in a Shuffleboard tab. Layouts can contain widgets and other layouts. */
public class ShuffleboardLayout extends ShuffleboardComponent<ShuffleboardLayout>
implements ShuffleboardContainer {
private final ContainerHelper m_helper = new ContainerHelper(this);
@@ -60,50 +54,43 @@
}
@Override
- public SuppliedValueWidget<String> addString(String title,
- Supplier<String> valueSupplier)
+ public SuppliedValueWidget<String> addString(String title, Supplier<String> valueSupplier)
throws IllegalArgumentException {
return m_helper.addString(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<Double> addNumber(String title,
- DoubleSupplier valueSupplier)
+ public SuppliedValueWidget<Double> addNumber(String title, DoubleSupplier valueSupplier)
throws IllegalArgumentException {
return m_helper.addNumber(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<Boolean> addBoolean(String title,
- BooleanSupplier valueSupplier)
+ public SuppliedValueWidget<Boolean> addBoolean(String title, BooleanSupplier valueSupplier)
throws IllegalArgumentException {
return m_helper.addBoolean(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<String[]> addStringArray(String title,
- Supplier<String[]> valueSupplier)
- throws IllegalArgumentException {
+ public SuppliedValueWidget<String[]> addStringArray(
+ String title, Supplier<String[]> valueSupplier) throws IllegalArgumentException {
return m_helper.addStringArray(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<double[]> addDoubleArray(String title,
- Supplier<double[]> valueSupplier)
- throws IllegalArgumentException {
+ public SuppliedValueWidget<double[]> addDoubleArray(
+ String title, Supplier<double[]> valueSupplier) throws IllegalArgumentException {
return m_helper.addDoubleArray(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<boolean[]> addBooleanArray(String title,
- Supplier<boolean[]> valueSupplier)
- throws IllegalArgumentException {
+ public SuppliedValueWidget<boolean[]> addBooleanArray(
+ String title, Supplier<boolean[]> valueSupplier) throws IllegalArgumentException {
return m_helper.addBooleanArray(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<byte[]> addRaw(String title,
- Supplier<byte[]> valueSupplier)
+ public SuppliedValueWidget<byte[]> addRaw(String title, Supplier<byte[]> valueSupplier)
throws IllegalArgumentException {
return m_helper.addRaw(title, valueSupplier);
}
@@ -117,5 +104,4 @@
component.buildInto(table, metaTable.getSubTable(component.getTitle()));
}
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardRoot.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardRoot.java
index a32af69..fa6cd08 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardRoot.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardRoot.java
@@ -1,20 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
/**
- * The root of the data placed in Shuffleboard. It contains the tabs, but no data is placed
- * directly in the root.
+ * The root of the data placed in Shuffleboard. It contains the tabs, but no data is placed directly
+ * in the root.
*
* <p>This class is package-private to minimize API surface area.
*/
interface ShuffleboardRoot {
-
/**
* Gets the tab with the given title, creating it if it does not already exist.
*
@@ -23,24 +19,18 @@
*/
ShuffleboardTab getTab(String title);
- /**
- * Updates all tabs.
- */
+ /** Updates all tabs. */
void update();
- /**
- * Enables all widgets in Shuffleboard that offer user control over actuators.
- */
+ /** Enables all widgets in Shuffleboard that offer user control over actuators. */
void enableActuatorWidgets();
- /**
- * Disables all widgets in Shuffleboard that offer user control over actuators.
- */
+ /** Disables all widgets in Shuffleboard that offer user control over actuators. */
void disableActuatorWidgets();
/**
- * Selects the tab in the dashboard with the given index in the range [0..n-1], where <i>n</i>
- * is the number of tabs in the dashboard at the time this method is called.
+ * Selects the tab in the dashboard with the given index in the range [0..n-1], where <i>n</i> is
+ * the number of tabs in the dashboard at the time this method is called.
*
* @param index the index of the tab to select
*/
@@ -52,5 +42,4 @@
* @param title the title of the tab to select
*/
void selectTab(String title);
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardTab.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardTab.java
index 5d575df..172d86f 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardTab.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardTab.java
@@ -1,25 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.util.sendable.Sendable;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.BooleanSupplier;
import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
-import edu.wpi.first.networktables.NetworkTable;
-import edu.wpi.first.wpilibj.Sendable;
-
/**
- * Represents a tab in the Shuffleboard dashboard. Widgets can be added to the tab with
- * {@link #add(Sendable)}, {@link #add(String, Object)}, and {@link #add(String, Sendable)}. Widgets
- * can also be added to layouts with {@link #getLayout(String, String)}; layouts can be nested
+ * Represents a tab in the Shuffleboard dashboard. Widgets can be added to the tab with {@link
+ * #add(Sendable)}, {@link #add(String, Object)}, and {@link #add(String, Sendable)}. Widgets can
+ * also be added to layouts with {@link #getLayout(String, String)}; layouts can be nested
* arbitrarily deep (note that too many levels may make deeper components unusable).
*/
public final class ShuffleboardTab implements ShuffleboardContainer {
@@ -72,50 +68,43 @@
}
@Override
- public SuppliedValueWidget<String> addString(String title,
- Supplier<String> valueSupplier)
+ public SuppliedValueWidget<String> addString(String title, Supplier<String> valueSupplier)
throws IllegalArgumentException {
return m_helper.addString(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<Double> addNumber(String title,
- DoubleSupplier valueSupplier)
+ public SuppliedValueWidget<Double> addNumber(String title, DoubleSupplier valueSupplier)
throws IllegalArgumentException {
return m_helper.addNumber(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<Boolean> addBoolean(String title,
- BooleanSupplier valueSupplier)
+ public SuppliedValueWidget<Boolean> addBoolean(String title, BooleanSupplier valueSupplier)
throws IllegalArgumentException {
return m_helper.addBoolean(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<String[]> addStringArray(String title,
- Supplier<String[]> valueSupplier)
- throws IllegalArgumentException {
+ public SuppliedValueWidget<String[]> addStringArray(
+ String title, Supplier<String[]> valueSupplier) throws IllegalArgumentException {
return m_helper.addStringArray(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<double[]> addDoubleArray(String title,
- Supplier<double[]> valueSupplier)
- throws IllegalArgumentException {
+ public SuppliedValueWidget<double[]> addDoubleArray(
+ String title, Supplier<double[]> valueSupplier) throws IllegalArgumentException {
return m_helper.addDoubleArray(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<boolean[]> addBooleanArray(String title,
- Supplier<boolean[]> valueSupplier)
- throws IllegalArgumentException {
+ public SuppliedValueWidget<boolean[]> addBooleanArray(
+ String title, Supplier<boolean[]> valueSupplier) throws IllegalArgumentException {
return m_helper.addBooleanArray(title, valueSupplier);
}
@Override
- public SuppliedValueWidget<byte[]> addRaw(String title,
- Supplier<byte[]> valueSupplier)
+ public SuppliedValueWidget<byte[]> addRaw(String title, Supplier<byte[]> valueSupplier)
throws IllegalArgumentException {
return m_helper.addRaw(title, valueSupplier);
}
@@ -128,5 +117,4 @@
component.buildInto(tabTable, metaTable.getSubTable(component.getTitle()));
}
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardValue.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardValue.java
index 8bfa6c3..88f4389 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardValue.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardValue.java
@@ -1,18 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
import edu.wpi.first.networktables.NetworkTable;
interface ShuffleboardValue {
-
/**
* Gets the title of this Shuffleboard value.
+ *
+ * @return The title of this Shuffleboard value.
*/
String getTitle();
@@ -20,12 +18,10 @@
* Builds the entries for this value.
*
* @param parentTable the table containing all the data for the parent. Values that require a
- * complex entry or table structure should call {@code
- * parentTable.getSubTable(getTitle())} to get the table to put data into.
- * Values that only use a single entry should call {@code
- * parentTable.getEntry(getTitle())} to get that entry.
- * @param metaTable the table containing all the metadata for this value and its sub-values
+ * complex entry or table structure should call {@code parentTable.getSubTable(getTitle())} to
+ * get the table to put data into. Values that only use a single entry should call {@code
+ * parentTable.getEntry(getTitle())} to get that entry.
+ * @param metaTable the table containing all the metadata for this value and its sub-values
*/
void buildInto(NetworkTable parentTable, NetworkTable metaTable);
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardWidget.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardWidget.java
index c929f4a..39ce036 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardWidget.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardWidget.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
@@ -16,7 +13,6 @@
*/
abstract class ShuffleboardWidget<W extends ShuffleboardWidget<W>>
extends ShuffleboardComponent<W> {
-
ShuffleboardWidget(ShuffleboardContainer parent, String title) {
super(parent, title);
}
@@ -36,15 +32,15 @@
/**
* Sets the type of widget used to display the data. If not set, the default widget type will be
* used. This method should only be used to use a widget that does not come built into
- * Shuffleboard (i.e. one that comes with a custom or third-party plugin). To use a widget that
- * is built into Shuffleboard, use {@link #withWidget(WidgetType)} and {@link BuiltInWidgets}.
+ * Shuffleboard (i.e. one that comes with a custom or third-party plugin). To use a widget that is
+ * built into Shuffleboard, use {@link #withWidget(WidgetType)} and {@link BuiltInWidgets}.
*
* @param widgetType the type of the widget used to display the data
* @return this widget object
*/
+ @SuppressWarnings("unchecked")
public final W withWidget(String widgetType) {
setType(widgetType);
return (W) this;
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SimpleWidget.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SimpleWidget.java
index c645baa..2043432 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SimpleWidget.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SimpleWidget.java
@@ -1,18 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
-/**
- * A Shuffleboard widget that handles a single data point such as a number or string.
- */
+/** A Shuffleboard widget that handles a single data point such as a number or string. */
public final class SimpleWidget extends ShuffleboardWidget<SimpleWidget> {
private NetworkTableEntry m_entry;
@@ -22,6 +17,8 @@
/**
* Gets the NetworkTable entry that contains the data for this widget.
+ *
+ * @return The NetworkTable entry that contains the data for this widget.
*/
public NetworkTableEntry getEntry() {
if (m_entry == null) {
@@ -46,5 +43,4 @@
ShuffleboardTab tab = (ShuffleboardTab) parent;
tab.getRoot().update();
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SuppliedValueWidget.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SuppliedValueWidget.java
index c7c9e8b..497b30f 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SuppliedValueWidget.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/SuppliedValueWidget.java
@@ -1,17 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
-import java.util.function.BiConsumer;
-import java.util.function.Supplier;
-
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
+import java.util.function.BiConsumer;
+import java.util.function.Supplier;
/**
* A Shuffleboard widget whose value is provided by user code.
@@ -25,15 +21,16 @@
/**
* Package-private constructor for use by the Shuffleboard API.
*
- * @param parent the parent container for the widget
- * @param title the title of the widget
+ * @param parent the parent container for the widget
+ * @param title the title of the widget
* @param supplier the supplier for values to place in the NetworkTable entry
- * @param setter the function for placing values in the NetworkTable entry
+ * @param setter the function for placing values in the NetworkTable entry
*/
- SuppliedValueWidget(ShuffleboardContainer parent,
- String title,
- Supplier<T> supplier,
- BiConsumer<NetworkTableEntry, T> setter) {
+ SuppliedValueWidget(
+ ShuffleboardContainer parent,
+ String title,
+ Supplier<T> supplier,
+ BiConsumer<NetworkTableEntry, T> setter) {
super(parent, title);
this.m_supplier = supplier;
this.m_setter = setter;
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/WidgetType.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/WidgetType.java
index 1e8242f..3033f8e 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/WidgetType.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/shuffleboard/WidgetType.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
@@ -16,6 +13,8 @@
public interface WidgetType {
/**
* Gets the string type of the widget as defined by that widget in Shuffleboard.
+ *
+ * @return The string type of the widget.
*/
String getWidgetName();
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXL345Sim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXL345Sim.java
new file mode 100644
index 0000000..c50c2f8
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXL345Sim.java
@@ -0,0 +1,62 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import edu.wpi.first.hal.SimDouble;
+import edu.wpi.first.wpilibj.ADXL345_I2C;
+import edu.wpi.first.wpilibj.ADXL345_SPI;
+import java.util.Objects;
+
+public class ADXL345Sim {
+ protected SimDouble m_simX;
+ protected SimDouble m_simY;
+ protected SimDouble m_simZ;
+
+ /**
+ * Constructor.
+ *
+ * @param device The device to simulate
+ */
+ public ADXL345Sim(ADXL345_SPI device) {
+ SimDeviceSim simDevice = new SimDeviceSim("Accel:ADXL345_SPI" + "[" + device.getPort() + "]");
+ initSim(simDevice);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param device The device to simulate
+ */
+ public ADXL345Sim(ADXL345_I2C device) {
+ SimDeviceSim simDevice =
+ new SimDeviceSim(
+ "Accel:ADXL345_I2C" + "[" + device.getPort() + "," + device.getDeviceAddress() + "]");
+ initSim(simDevice);
+ }
+
+ private void initSim(SimDeviceSim simDevice) {
+ Objects.requireNonNull(simDevice);
+
+ m_simX = simDevice.getDouble("x");
+ m_simY = simDevice.getDouble("y");
+ m_simZ = simDevice.getDouble("z");
+
+ Objects.requireNonNull(m_simX);
+ Objects.requireNonNull(m_simY);
+ Objects.requireNonNull(m_simZ);
+ }
+
+ public void setX(double x) {
+ m_simX.set(x);
+ }
+
+ public void setY(double y) {
+ m_simY.set(y);
+ }
+
+ public void setZ(double z) {
+ m_simZ.set(z);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXL362Sim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXL362Sim.java
new file mode 100644
index 0000000..76df8bd
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXL362Sim.java
@@ -0,0 +1,48 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import edu.wpi.first.hal.SimDouble;
+import edu.wpi.first.wpilibj.ADXL362;
+import java.util.Objects;
+
+public class ADXL362Sim {
+ protected SimDouble m_simX;
+ protected SimDouble m_simY;
+ protected SimDouble m_simZ;
+
+ /**
+ * Constructor.
+ *
+ * @param device The device to simulate
+ */
+ public ADXL362Sim(ADXL362 device) {
+ SimDeviceSim wrappedSimDevice =
+ new SimDeviceSim("Accel:ADXL362" + "[" + device.getPort() + "]");
+ initSim(wrappedSimDevice);
+ }
+
+ private void initSim(SimDeviceSim wrappedSimDevice) {
+ m_simX = wrappedSimDevice.getDouble("x");
+ m_simY = wrappedSimDevice.getDouble("y");
+ m_simZ = wrappedSimDevice.getDouble("z");
+
+ Objects.requireNonNull(m_simX);
+ Objects.requireNonNull(m_simY);
+ Objects.requireNonNull(m_simZ);
+ }
+
+ public void setX(double x) {
+ m_simX.set(x);
+ }
+
+ public void setY(double y) {
+ m_simY.set(y);
+ }
+
+ public void setZ(double z) {
+ m_simZ.set(z);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXRS450_GyroSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXRS450_GyroSim.java
index 950efef..27e06a3 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXRS450_GyroSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ADXRS450_GyroSim.java
@@ -1,19 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.wpilibj.ADXRS450_Gyro;
-/**
- * Class to control a simulated ADXRS450 gyroscope.
- */
-@SuppressWarnings("TypeName")
+/** Class to control a simulated ADXRS450 gyroscope. */
+@SuppressWarnings({"TypeName", "AbbreviationAsWordInName"})
public class ADXRS450_GyroSim {
private final SimDouble m_simAngle;
private final SimDouble m_simRate;
@@ -24,9 +19,9 @@
* @param gyro ADXRS450_Gyro to simulate
*/
public ADXRS450_GyroSim(ADXRS450_Gyro gyro) {
- SimDeviceSim wrappedSimDevice = new SimDeviceSim("ADXRS450_Gyro" + "[" + gyro.getPort() + "]");
- m_simAngle = wrappedSimDevice.getDouble("Angle");
- m_simRate = wrappedSimDevice.getDouble("Rate");
+ SimDeviceSim wrappedSimDevice = new SimDeviceSim("Gyro:ADXRS450" + "[" + gyro.getPort() + "]");
+ m_simAngle = wrappedSimDevice.getDouble("angle_x");
+ m_simRate = wrappedSimDevice.getDouble("rate_x");
}
/**
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSim.java
index 81c9a7b..bf543c0 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -13,15 +10,11 @@
import edu.wpi.first.wpilibj.AddressableLED;
import java.util.NoSuchElementException;
-/**
- * Class to control a simulated addressable LED.
- */
+/** Class to control a simulated addressable LED. */
public class AddressableLEDSim {
private final int m_index;
- /**
- * Constructs for the first addressable LED.
- */
+ /** Constructs for the first addressable LED. */
public AddressableLEDSim() {
m_index = 0;
}
@@ -57,8 +50,8 @@
}
/**
- * Creates an AddressableLEDSim for a simulated index.
- * The index is incremented for each simulated AddressableLED.
+ * Creates an AddressableLEDSim for a simulated index. The index is incremented for each simulated
+ * AddressableLED.
*
* @param index simulator index
* @return Simulated object
@@ -67,61 +60,161 @@
return new AddressableLEDSim(index);
}
+ /**
+ * Register a callback on the Initialized property.
+ *
+ * @param callback the callback that will be called whenever the Initialized property is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AddressableLEDDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check if initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return AddressableLEDDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Change the Initialized value of the LED strip.
+ *
+ * @param initialized the new value
+ */
public void setInitialized(boolean initialized) {
AddressableLEDDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback on the output port.
+ *
+ * @param callback the callback that will be called whenever the output port is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerOutputPortCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AddressableLEDDataJNI.registerOutputPortCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelOutputPortCallback);
}
+
+ /**
+ * Get the output port.
+ *
+ * @return the output port
+ */
public int getOutputPort() {
return AddressableLEDDataJNI.getOutputPort(m_index);
}
+
+ /**
+ * Change the output port.
+ *
+ * @param outputPort the new output port
+ */
public void setOutputPort(int outputPort) {
AddressableLEDDataJNI.setOutputPort(m_index, outputPort);
}
+ /**
+ * Register a callback on the length.
+ *
+ * @param callback the callback that will be called whenever the length is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerLengthCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AddressableLEDDataJNI.registerLengthCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelLengthCallback);
}
+
+ /**
+ * Get the length of the LED strip.
+ *
+ * @return the length
+ */
public int getLength() {
return AddressableLEDDataJNI.getLength(m_index);
}
+
+ /**
+ * Change the length of the LED strip.
+ *
+ * @param length the new value
+ */
public void setLength(int length) {
AddressableLEDDataJNI.setLength(m_index, length);
}
+ /**
+ * Register a callback on whether the LEDs are running.
+ *
+ * @param callback the callback that will be called whenever the LED state is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerRunningCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AddressableLEDDataJNI.registerRunningCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelRunningCallback);
}
+
+ /**
+ * Check if the LEDs are running.
+ *
+ * @return true if they are
+ */
public boolean getRunning() {
return AddressableLEDDataJNI.getRunning(m_index);
}
+
+ /**
+ * Change whether the LEDs are active.
+ *
+ * @param running the new value
+ */
public void setRunning(boolean running) {
AddressableLEDDataJNI.setRunning(m_index, running);
}
+ /**
+ * Register a callback on the LED data.
+ *
+ * @param callback the callback that will be called whenever the LED data is changed
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerDataCallback(ConstBufferCallback callback) {
int uid = AddressableLEDDataJNI.registerDataCallback(m_index, callback);
return new CallbackStore(m_index, uid, AddressableLEDDataJNI::cancelDataCallback);
}
+
+ /**
+ * Get the LED data.
+ *
+ * @return the LED data
+ */
public byte[] getData() {
return AddressableLEDDataJNI.getData(m_index);
}
+
+ /**
+ * Change the LED data.
+ *
+ * @param data the new data
+ */
public void setData(byte[] data) {
AddressableLEDDataJNI.setData(m_index, data);
}
+ /** Reset all simulation data for this LED object. */
public void resetData() {
AddressableLEDDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogEncoderSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogEncoderSim.java
index e1b541f..6b11673 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogEncoderSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogEncoderSim.java
@@ -1,19 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.SimDouble;
+import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.wpilibj.AnalogEncoder;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
-/**
- * Class to control a simulated analog encoder.
- */
+/** Class to control a simulated analog encoder. */
public class AnalogEncoderSim {
private final SimDouble m_simPosition;
@@ -23,7 +18,8 @@
* @param encoder AnalogEncoder to simulate
*/
public AnalogEncoderSim(AnalogEncoder encoder) {
- SimDeviceSim wrappedSimDevice = new SimDeviceSim("AnalogEncoder" + "[" + encoder.getChannel() + "]");
+ SimDeviceSim wrappedSimDevice =
+ new SimDeviceSim("AnalogEncoder" + "[" + encoder.getChannel() + "]");
m_simPosition = wrappedSimDevice.getDouble("Position");
}
@@ -47,6 +43,8 @@
/**
* Get the simulated position.
+ *
+ * @return The simulated position.
*/
public double getTurns() {
return m_simPosition.get();
@@ -54,6 +52,8 @@
/**
* Get the position as a {@link Rotation2d}.
+ *
+ * @return The position as a {@link Rotation2d}.
*/
public Rotation2d getPosition() {
return Rotation2d.fromDegrees(getTurns() * 360.0);
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogGyroSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogGyroSim.java
index b204fae..87217aa 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogGyroSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogGyroSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -11,9 +8,7 @@
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.wpilibj.AnalogGyro;
-/**
- * Class to control a simulated analog gyro.
- */
+/** Class to control a simulated analog gyro. */
public class AnalogGyroSim {
private final int m_index;
@@ -35,39 +30,100 @@
m_index = channel;
}
+ /**
+ * Register a callback on the angle.
+ *
+ * @param callback the callback that will be called whenever the angle changes
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerAngleCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogGyroDataJNI.registerAngleCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogGyroDataJNI::cancelAngleCallback);
}
+
+ /**
+ * Get the current angle of the gyro.
+ *
+ * @return the angle measured by the gyro
+ */
public double getAngle() {
return AnalogGyroDataJNI.getAngle(m_index);
}
+
+ /**
+ * Change the angle measured by the gyro.
+ *
+ * @param angle the new value
+ */
public void setAngle(double angle) {
AnalogGyroDataJNI.setAngle(m_index, angle);
}
+ /**
+ * Register a callback on the rate.
+ *
+ * @param callback the callback that will be called whenever the rate changes
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerRateCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogGyroDataJNI.registerRateCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogGyroDataJNI::cancelRateCallback);
}
+
+ /**
+ * Get the rate of angle change on this gyro.
+ *
+ * @return the rate
+ */
public double getRate() {
return AnalogGyroDataJNI.getRate(m_index);
}
+
+ /**
+ * Change the rate of the gyro.
+ *
+ * @param rate the new rate
+ */
public void setRate(double rate) {
AnalogGyroDataJNI.setRate(m_index, rate);
}
+ /**
+ * Register a callback on whether the gyro is initialized.
+ *
+ * @param callback the callback that will be called whenever the gyro is initialized
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogGyroDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogGyroDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check if the gyro is initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return AnalogGyroDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Set whether this gyro is initialized.
+ *
+ * @param initialized the new value
+ */
public void setInitialized(boolean initialized) {
AnalogGyroDataJNI.setInitialized(m_index, initialized);
}
+ /** Reset all simulation data for this object. */
public void resetData() {
AnalogGyroDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogInputSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogInputSim.java
index 1709d6a..87dce71 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogInputSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogInputSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -11,9 +8,7 @@
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.wpilibj.AnalogInput;
-/**
- * Class to control a simulated analog input.
- */
+/** Class to control a simulated analog input. */
public class AnalogInputSim {
private final int m_index;
@@ -35,105 +30,293 @@
m_index = channel;
}
+ /**
+ * Register a callback on whether the analog input is initialized.
+ *
+ * @param callback the callback that will be called whenever the analog input is initialized
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogInDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check if this analog input has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return AnalogInDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Change whether this analog input has been initialized.
+ *
+ * @param initialized the new value
+ */
public void setInitialized(boolean initialized) {
AnalogInDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback on the number of average bits.
+ *
+ * @param callback the callback that will be called whenever the number of average bits is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerAverageBitsCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogInDataJNI.registerAverageBitsCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAverageBitsCallback);
}
+
+ /**
+ * Get the number of average bits.
+ *
+ * @return the number of average bits
+ */
public int getAverageBits() {
return AnalogInDataJNI.getAverageBits(m_index);
}
+
+ /**
+ * Change the number of average bits.
+ *
+ * @param averageBits the new value
+ */
public void setAverageBits(int averageBits) {
AnalogInDataJNI.setAverageBits(m_index, averageBits);
}
- public CallbackStore registerOversampleBitsCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the amount of oversampling bits.
+ *
+ * @param callback the callback that will be called whenever the oversampling bits are changed.
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerOversampleBitsCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = AnalogInDataJNI.registerOversampleBitsCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelOversampleBitsCallback);
}
+
+ /**
+ * Get the amount of oversampling bits.
+ *
+ * @return the amount of oversampling bits
+ */
public int getOversampleBits() {
return AnalogInDataJNI.getOversampleBits(m_index);
}
+
+ /**
+ * Change the amount of oversampling bits.
+ *
+ * @param oversampleBits the new value
+ */
public void setOversampleBits(int oversampleBits) {
AnalogInDataJNI.setOversampleBits(m_index, oversampleBits);
}
+ /**
+ * Register a callback on the voltage.
+ *
+ * @param callback the callback that will be called whenever the voltage is changed.
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerVoltageCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogInDataJNI.registerVoltageCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelVoltageCallback);
}
+
+ /**
+ * Get the voltage.
+ *
+ * @return the voltage
+ */
public double getVoltage() {
return AnalogInDataJNI.getVoltage(m_index);
}
+
+ /**
+ * Change the voltage.
+ *
+ * @param voltage the new value
+ */
public void setVoltage(double voltage) {
AnalogInDataJNI.setVoltage(m_index, voltage);
}
- public CallbackStore registerAccumulatorInitializedCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = AnalogInDataJNI.registerAccumulatorInitializedCallback(m_index, callback, initialNotify);
+ /**
+ * Register a callback on whether the accumulator is initialized.
+ *
+ * @param callback the callback that will be called whenever the accumulator is initialized
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerAccumulatorInitializedCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid =
+ AnalogInDataJNI.registerAccumulatorInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorInitializedCallback);
}
+
+ /**
+ * Check if the accumulator has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getAccumulatorInitialized() {
return AnalogInDataJNI.getAccumulatorInitialized(m_index);
}
+
+ /**
+ * Change whether the accumulator has been initialized.
+ *
+ * @param accumulatorInitialized the new value
+ */
public void setAccumulatorInitialized(boolean accumulatorInitialized) {
AnalogInDataJNI.setAccumulatorInitialized(m_index, accumulatorInitialized);
}
- public CallbackStore registerAccumulatorValueCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the accumulator value.
+ *
+ * @param callback the callback that will be called whenever the accumulator value is changed.
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerAccumulatorValueCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = AnalogInDataJNI.registerAccumulatorValueCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorValueCallback);
}
+
+ /**
+ * Get the accumulator value.
+ *
+ * @return the accumulator value
+ */
public long getAccumulatorValue() {
return AnalogInDataJNI.getAccumulatorValue(m_index);
}
+
+ /**
+ * Change the accumulator value.
+ *
+ * @param accumulatorValue the new value
+ */
public void setAccumulatorValue(long accumulatorValue) {
AnalogInDataJNI.setAccumulatorValue(m_index, accumulatorValue);
}
- public CallbackStore registerAccumulatorCountCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the accumulator count.
+ *
+ * @param callback the callback that will be called whenever the accumulator count is changed.
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerAccumulatorCountCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = AnalogInDataJNI.registerAccumulatorCountCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorCountCallback);
}
+
+ /**
+ * Get the accumulator count.
+ *
+ * @return the accumulator count.
+ */
public long getAccumulatorCount() {
return AnalogInDataJNI.getAccumulatorCount(m_index);
}
+
+ /**
+ * Change the accumulator count.
+ *
+ * @param accumulatorCount the new count.
+ */
public void setAccumulatorCount(long accumulatorCount) {
AnalogInDataJNI.setAccumulatorCount(m_index, accumulatorCount);
}
- public CallbackStore registerAccumulatorCenterCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the accumulator center.
+ *
+ * @param callback the callback that will be called whenever the accumulator center is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerAccumulatorCenterCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = AnalogInDataJNI.registerAccumulatorCenterCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorCenterCallback);
}
+
+ /**
+ * Get the accumulator center.
+ *
+ * @return the accumulator center
+ */
public int getAccumulatorCenter() {
return AnalogInDataJNI.getAccumulatorCenter(m_index);
}
+
+ /**
+ * Change the accumulator center.
+ *
+ * @param accumulatorCenter the new center
+ */
public void setAccumulatorCenter(int accumulatorCenter) {
AnalogInDataJNI.setAccumulatorCenter(m_index, accumulatorCenter);
}
- public CallbackStore registerAccumulatorDeadbandCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the accumulator deadband.
+ *
+ * @param callback the callback that will be called whenever the accumulator deadband is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerAccumulatorDeadbandCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = AnalogInDataJNI.registerAccumulatorDeadbandCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogInDataJNI::cancelAccumulatorDeadbandCallback);
}
+
+ /**
+ * Get the accumulator deadband.
+ *
+ * @return the accumulator deadband
+ */
public int getAccumulatorDeadband() {
return AnalogInDataJNI.getAccumulatorDeadband(m_index);
}
+
+ /**
+ * Change the accumulator deadband.
+ *
+ * @param accumulatorDeadband the new deadband
+ */
public void setAccumulatorDeadband(int accumulatorDeadband) {
AnalogInDataJNI.setAccumulatorDeadband(m_index, accumulatorDeadband);
}
+ /** Reset all simulation data for this object. */
public void resetData() {
AnalogInDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogOutputSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogOutputSim.java
index 077a2eb..985fcd9 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogOutputSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogOutputSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -11,9 +8,7 @@
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.wpilibj.AnalogOutput;
-/**
- * Class to control a simulated analog output.
- */
+/** Class to control a simulated analog output. */
public class AnalogOutputSim {
private final int m_index;
@@ -35,28 +30,69 @@
m_index = channel;
}
+ /**
+ * Register a callback to be run whenever the voltage changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerVoltageCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogOutDataJNI.registerVoltageCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogOutDataJNI::cancelVoltageCallback);
}
+
+ /**
+ * Read the analog output voltage.
+ *
+ * @return the voltage on this analog output
+ */
public double getVoltage() {
return AnalogOutDataJNI.getVoltage(m_index);
}
+
+ /**
+ * Set the analog output voltage.
+ *
+ * @param voltage the new voltage on this analog output
+ */
public void setVoltage(double voltage) {
AnalogOutDataJNI.setVoltage(m_index, voltage);
}
+ /**
+ * Register a callback to be run when this analog output is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogOutDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogOutDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check whether this analog output has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return AnalogOutDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Define whether this analog output has been initialized.
+ *
+ * @param initialized whether this object is initialized
+ */
public void setInitialized(boolean initialized) {
AnalogOutDataJNI.setInitialized(m_index, initialized);
}
+ /** Reset all simulation data on this object. */
public void resetData() {
AnalogOutDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogTriggerSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogTriggerSim.java
index 6916fdc..58d51b1 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogTriggerSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/AnalogTriggerSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -12,9 +9,7 @@
import edu.wpi.first.wpilibj.AnalogTrigger;
import java.util.NoSuchElementException;
-/**
- * Class to control a simulated analog trigger.
- */
+/** Class to control a simulated analog trigger. */
public class AnalogTriggerSim {
private final int m_index;
@@ -47,8 +42,8 @@
}
/**
- * Creates an AnalogTriggerSim for a simulated index.
- * The index is incremented for each simulated AnalogTrigger.
+ * Creates an AnalogTriggerSim for a simulated index. The index is incremented for each simulated
+ * AnalogTrigger.
*
* @param index simulator index
* @return Simulated object
@@ -57,39 +52,104 @@
return new AnalogTriggerSim(index);
}
+ /**
+ * Register a callback on whether the analog trigger is initialized.
+ *
+ * @param callback the callback that will be called whenever the analog trigger is initialized
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AnalogTriggerDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogTriggerDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check if this analog trigger has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return AnalogTriggerDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Change whether this analog trigger has been initialized.
+ *
+ * @param initialized the new value
+ */
public void setInitialized(boolean initialized) {
AnalogTriggerDataJNI.setInitialized(m_index, initialized);
}
- public CallbackStore registerTriggerLowerBoundCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = AnalogTriggerDataJNI.registerTriggerLowerBoundCallback(m_index, callback, initialNotify);
+ /**
+ * Register a callback on the lower bound.
+ *
+ * @param callback the callback that will be called whenever the lower bound is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerTriggerLowerBoundCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid =
+ AnalogTriggerDataJNI.registerTriggerLowerBoundCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogTriggerDataJNI::cancelTriggerLowerBoundCallback);
}
+
+ /**
+ * Get the lower bound.
+ *
+ * @return the lower bound
+ */
public double getTriggerLowerBound() {
return AnalogTriggerDataJNI.getTriggerLowerBound(m_index);
}
+
+ /**
+ * Change the lower bound.
+ *
+ * @param triggerLowerBound the new lower bound
+ */
public void setTriggerLowerBound(double triggerLowerBound) {
AnalogTriggerDataJNI.setTriggerLowerBound(m_index, triggerLowerBound);
}
- public CallbackStore registerTriggerUpperBoundCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = AnalogTriggerDataJNI.registerTriggerUpperBoundCallback(m_index, callback, initialNotify);
+ /**
+ * Register a callback on the upper bound.
+ *
+ * @param callback the callback that will be called whenever the upper bound is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerTriggerUpperBoundCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid =
+ AnalogTriggerDataJNI.registerTriggerUpperBoundCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AnalogTriggerDataJNI::cancelTriggerUpperBoundCallback);
}
+
+ /**
+ * Get the upper bound.
+ *
+ * @return the upper bound
+ */
public double getTriggerUpperBound() {
return AnalogTriggerDataJNI.getTriggerUpperBound(m_index);
}
+
+ /**
+ * Change the upper bound.
+ *
+ * @param triggerUpperBound the new upper bound
+ */
public void setTriggerUpperBound(double triggerUpperBound) {
AnalogTriggerDataJNI.setTriggerUpperBound(m_index, triggerUpperBound);
}
+ /** Reset all simulation data for this object. */
public void resetData() {
AnalogTriggerDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/BatterySim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/BatterySim.java
index 0150ed4..78c9888 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/BatterySim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/BatterySim.java
@@ -1,34 +1,28 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import edu.wpi.first.wpilibj.RobotController;
-
+/** A utility class to simulate the robot battery. */
public final class BatterySim {
private BatterySim() {
// Utility class
}
/**
- * Calculate the loaded battery voltage. Use this with
- * {@link RoboRioSim#setVInVoltage(double)} to set the simulated battery
- * voltage, which can then be retrieved with the {@link RobotController#getBatteryVoltage()}
- * method.
+ * Calculate the loaded battery voltage. Use this with {@link RoboRioSim#setVInVoltage(double)} to
+ * set the simulated battery voltage, which can then be retrieved with the {@link
+ * edu.wpi.first.wpilibj.RobotController#getBatteryVoltage()} method.
*
* @param nominalVoltage The nominal battery voltage. Usually 12v.
- * @param resistanceOhms The forward resistance of the battery. Most batteries are at or
- * below 20 milliohms.
- * @param currents The currents drawn from the battery.
+ * @param resistanceOhms The forward resistance of the battery. Most batteries are at or below 20
+ * milliohms.
+ * @param currents The currents drawn from the battery.
* @return The battery's voltage under load.
*/
- public static double calculateLoadedBatteryVoltage(double nominalVoltage,
- double resistanceOhms,
- double... currents) {
+ public static double calculateLoadedBatteryVoltage(
+ double nominalVoltage, double resistanceOhms, double... currents) {
double retval = nominalVoltage;
for (var current : currents) {
retval -= current * resistanceOhms;
@@ -37,11 +31,10 @@
}
/**
- * Calculate the loaded battery voltage. Use this with
- * {@link RoboRioSim#setVInVoltage(double)} to set the simulated battery
- * voltage, which can then be retrieved with the {@link RobotController#getBatteryVoltage()}
- * method. This function assumes a nominal voltage of 12v and a resistance of 20 milliohms
- * (0.020 ohms)
+ * Calculate the loaded battery voltage. Use this with {@link RoboRioSim#setVInVoltage(double)} to
+ * set the simulated battery voltage, which can then be retrieved with the {@link
+ * edu.wpi.first.wpilibj.RobotController#getBatteryVoltage()} method. This function assumes a
+ * nominal voltage of 12v and a resistance of 20 milliohms (0.020 ohms)
*
* @param currents The currents drawn from the battery.
* @return The battery's voltage under load.
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/BuiltInAccelerometerSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/BuiltInAccelerometerSim.java
index 8905542..5714a2d 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/BuiltInAccelerometerSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/BuiltInAccelerometerSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -11,15 +8,11 @@
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.wpilibj.BuiltInAccelerometer;
-/**
- * Class to control a simulated built-in accelerometer.
- */
+/** Class to control a simulated built-in accelerometer. */
public class BuiltInAccelerometerSim {
private final int m_index;
- /**
- * Constructs for the first built-in accelerometer.
- */
+ /** Constructs for the first built-in accelerometer. */
public BuiltInAccelerometerSim() {
m_index = 0;
}
@@ -34,61 +27,165 @@
m_index = 0;
}
+ /**
+ * Register a callback to be run when this accelerometer activates.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerActiveCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AccelerometerDataJNI.registerActiveCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelActiveCallback);
}
+
+ /**
+ * Check whether the accelerometer is active.
+ *
+ * @return true if active
+ */
public boolean getActive() {
return AccelerometerDataJNI.getActive(m_index);
}
+
+ /**
+ * Define whether this accelerometer is active.
+ *
+ * @param active the new state
+ */
public void setActive(boolean active) {
AccelerometerDataJNI.setActive(m_index, active);
}
+ /**
+ * Register a callback to be run whenever the range changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerRangeCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AccelerometerDataJNI.registerRangeCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelRangeCallback);
}
+
+ /**
+ * Check the range of this accelerometer.
+ *
+ * @return the accelerometer range
+ */
public int getRange() {
return AccelerometerDataJNI.getRange(m_index);
}
+
+ /**
+ * Change the range of this accelerometer.
+ *
+ * @param range the new accelerometer range
+ */
public void setRange(int range) {
AccelerometerDataJNI.setRange(m_index, range);
}
+ /**
+ * Register a callback to be run whenever the X axis value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerXCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AccelerometerDataJNI.registerXCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelXCallback);
}
+
+ /**
+ * Measure the X axis value.
+ *
+ * @return the X axis measurement
+ */
public double getX() {
return AccelerometerDataJNI.getX(m_index);
}
+
+ /**
+ * Change the X axis value of the accelerometer.
+ *
+ * @param x the new reading of the X axis
+ */
+ @SuppressWarnings("ParameterName")
public void setX(double x) {
AccelerometerDataJNI.setX(m_index, x);
}
+ /**
+ * Register a callback to be run whenever the Y axis value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerYCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AccelerometerDataJNI.registerYCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelYCallback);
}
+
+ /**
+ * Measure the Y axis value.
+ *
+ * @return the Y axis measurement
+ */
public double getY() {
return AccelerometerDataJNI.getY(m_index);
}
+
+ /**
+ * Change the Y axis value of the accelerometer.
+ *
+ * @param y the new reading of the Y axis
+ */
+ @SuppressWarnings("ParameterName")
public void setY(double y) {
AccelerometerDataJNI.setY(m_index, y);
}
+ /**
+ * Register a callback to be run whenever the Z axis value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerZCallback(NotifyCallback callback, boolean initialNotify) {
int uid = AccelerometerDataJNI.registerZCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, AccelerometerDataJNI::cancelZCallback);
}
+
+ /**
+ * Measure the Z axis value.
+ *
+ * @return the Z axis measurement
+ */
public double getZ() {
return AccelerometerDataJNI.getZ(m_index);
}
+
+ /**
+ * Change the Z axis value of the accelerometer.
+ *
+ * @param z the new reading of the Z axis
+ */
+ @SuppressWarnings("ParameterName")
public void setZ(double z) {
AccelerometerDataJNI.setZ(m_index, z);
}
+ /** Reset all simulation data of this object. */
public void resetData() {
AccelerometerDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/CTREPCMSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/CTREPCMSim.java
new file mode 100644
index 0000000..12ae153
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/CTREPCMSim.java
@@ -0,0 +1,239 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import edu.wpi.first.hal.simulation.CTREPCMDataJNI;
+import edu.wpi.first.hal.simulation.NotifyCallback;
+import edu.wpi.first.wpilibj.PneumaticsBase;
+import edu.wpi.first.wpilibj.SensorUtil;
+
+/** Class to control a simulated Pneumatic Control Module (PCM). */
+@SuppressWarnings("AbbreviationAsWordInName")
+public class CTREPCMSim {
+ private final int m_index;
+
+ /** Constructs for the default PCM. */
+ public CTREPCMSim() {
+ m_index = SensorUtil.getDefaultCTREPCMModule();
+ }
+
+ /**
+ * Constructs from a PCM module number (CAN ID).
+ *
+ * @param module module number
+ */
+ public CTREPCMSim(int module) {
+ m_index = module;
+ }
+
+ /**
+ * Constructs from a Compressor object.
+ *
+ * @param module PCM module to simulate
+ */
+ public CTREPCMSim(PneumaticsBase module) {
+ m_index = module.getModuleNumber();
+ }
+
+ /**
+ * Register a callback to be run when the solenoid output on a channel changes.
+ *
+ * @param channel the channel to monitor
+ * @param callback the callback
+ * @param initialNotify should the callback be run with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerSolenoidOutputCallback(
+ int channel, NotifyCallback callback, boolean initialNotify) {
+ int uid =
+ CTREPCMDataJNI.registerSolenoidOutputCallback(m_index, channel, callback, initialNotify);
+ return new CallbackStore(m_index, channel, uid, CTREPCMDataJNI::cancelSolenoidOutputCallback);
+ }
+
+ /**
+ * Check the solenoid output on a specific channel.
+ *
+ * @param channel the channel to check
+ * @return the solenoid output
+ */
+ public boolean getSolenoidOutput(int channel) {
+ return CTREPCMDataJNI.getSolenoidOutput(m_index, channel);
+ }
+
+ /**
+ * Change the solenoid output on a specific channel.
+ *
+ * @param channel the channel to check
+ * @param solenoidOutput the new solenoid output
+ */
+ public void setSolenoidOutput(int channel, boolean solenoidOutput) {
+ CTREPCMDataJNI.setSolenoidOutput(m_index, channel, solenoidOutput);
+ }
+
+ /**
+ * Register a callback to be run when the compressor is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+ int uid = CTREPCMDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, CTREPCMDataJNI::cancelInitializedCallback);
+ }
+
+ /**
+ * Check whether the compressor has been initialized.
+ *
+ * @return true if initialized
+ */
+ public boolean getInitialized() {
+ return CTREPCMDataJNI.getInitialized(m_index);
+ }
+
+ /**
+ * Define whether the compressor has been initialized.
+ *
+ * @param initialized whether the compressor is initialized
+ */
+ public void setInitialized(boolean initialized) {
+ CTREPCMDataJNI.setInitialized(m_index, initialized);
+ }
+
+ /**
+ * Register a callback to be run when the compressor activates.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerCompressorOnCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = CTREPCMDataJNI.registerCompressorOnCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, CTREPCMDataJNI::cancelCompressorOnCallback);
+ }
+
+ /**
+ * Check if the compressor is on.
+ *
+ * @return true if the compressor is active
+ */
+ public boolean getCompressorOn() {
+ return CTREPCMDataJNI.getCompressorOn(m_index);
+ }
+
+ /**
+ * Set whether the compressor is active.
+ *
+ * @param compressorOn the new value
+ */
+ public void setCompressorOn(boolean compressorOn) {
+ CTREPCMDataJNI.setCompressorOn(m_index, compressorOn);
+ }
+
+ /**
+ * Register a callback to be run whenever the closed loop state changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerClosedLoopEnabledCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = CTREPCMDataJNI.registerClosedLoopEnabledCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, CTREPCMDataJNI::cancelClosedLoopEnabledCallback);
+ }
+
+ /**
+ * Check whether the closed loop compressor control is active.
+ *
+ * @return true if active
+ */
+ public boolean getClosedLoopEnabled() {
+ return CTREPCMDataJNI.getClosedLoopEnabled(m_index);
+ }
+
+ /**
+ * Turn on/off the closed loop control of the compressor.
+ *
+ * @param closedLoopEnabled whether the control loop is active
+ */
+ public void setClosedLoopEnabled(boolean closedLoopEnabled) {
+ CTREPCMDataJNI.setClosedLoopEnabled(m_index, closedLoopEnabled);
+ }
+
+ /**
+ * Register a callback to be run whenever the pressure switch value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerPressureSwitchCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = CTREPCMDataJNI.registerPressureSwitchCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, CTREPCMDataJNI::cancelPressureSwitchCallback);
+ }
+
+ /**
+ * Check the value of the pressure switch.
+ *
+ * @return the pressure switch value
+ */
+ public boolean getPressureSwitch() {
+ return CTREPCMDataJNI.getPressureSwitch(m_index);
+ }
+
+ /**
+ * Set the value of the pressure switch.
+ *
+ * @param pressureSwitch the new value
+ */
+ public void setPressureSwitch(boolean pressureSwitch) {
+ CTREPCMDataJNI.setPressureSwitch(m_index, pressureSwitch);
+ }
+
+ /**
+ * Register a callback to be run whenever the compressor current changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerCompressorCurrentCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = CTREPCMDataJNI.registerCompressorCurrentCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, CTREPCMDataJNI::cancelCompressorCurrentCallback);
+ }
+
+ /**
+ * Read the compressor current.
+ *
+ * @return the current of the compressor connected to this module
+ */
+ public double getCompressorCurrent() {
+ return CTREPCMDataJNI.getCompressorCurrent(m_index);
+ }
+
+ /**
+ * Set the compressor current.
+ *
+ * @param compressorCurrent the new compressor current
+ */
+ public void setCompressorCurrent(double compressorCurrent) {
+ CTREPCMDataJNI.setCompressorCurrent(m_index, compressorCurrent);
+ }
+
+ /** Reset all simulation data for this object. */
+ public void resetData() {
+ CTREPCMDataJNI.resetData(m_index);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/CallbackStore.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/CallbackStore.java
index 3df142f..048d3c1 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/CallbackStore.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/CallbackStore.java
@@ -1,25 +1,33 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
+/** Manages simulation callbacks; each object is associated with a callback. */
public class CallbackStore implements AutoCloseable {
+ /** <b>Note: This interface is for simulation classes only. It should not be used by teams!</b> */
interface CancelCallbackFunc {
void cancel(int index, int uid);
}
+ /** <b>Note: This interface is for simulation classes only. It should not be used by teams!</b> */
interface CancelCallbackChannelFunc {
void cancel(int index, int channel, int uid);
}
+ /** <b>Note: This interface is for simulation classes only. It should not be used by teams!</b> */
interface CancelCallbackNoIndexFunc {
void cancel(int uid);
}
+ /**
+ * <b>Note: This constructor is for simulation classes only. It should not be called by teams!</b>
+ *
+ * @param index TODO
+ * @param uid TODO
+ * @param ccf TODO
+ */
public CallbackStore(int index, int uid, CancelCallbackFunc ccf) {
this.m_cancelType = kNormalCancel;
this.m_index = index;
@@ -27,6 +35,14 @@
this.m_cancelCallback = ccf;
}
+ /**
+ * <b>Note: This constructor is for simulation classes only. It should not be called by teams!</b>
+ *
+ * @param index TODO
+ * @param channel TODO
+ * @param uid TODO
+ * @param ccf TODO
+ */
public CallbackStore(int index, int channel, int uid, CancelCallbackChannelFunc ccf) {
this.m_cancelType = kChannelCancel;
this.m_index = index;
@@ -35,6 +51,12 @@
this.m_cancelCallbackChannel = ccf;
}
+ /**
+ * <b>Note: This constructor is for simulation classes only. It should not be called by teams!</b>
+ *
+ * @param uid TODO
+ * @param ccf TODO
+ */
public CallbackStore(int uid, CancelCallbackNoIndexFunc ccf) {
this.m_cancelType = kNoIndexCancel;
this.m_uid = uid;
@@ -52,6 +74,7 @@
private static final int kNoIndexCancel = 2;
private int m_cancelType;
+ /** Cancel the callback associated with this object. */
@Override
public void close() {
switch (m_cancelType) {
@@ -71,11 +94,12 @@
m_cancelType = -1;
}
+ @SuppressWarnings({"NoFinalizer", "deprecation"})
@Override
protected void finalize() throws Throwable {
try {
if (m_cancelType >= 0) {
- close(); // close open files
+ close(); // close open files
}
} finally {
super.finalize();
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DIOSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DIOSim.java
index 758d7e4..83afb74 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DIOSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DIOSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -12,9 +9,7 @@
import edu.wpi.first.wpilibj.DigitalInput;
import edu.wpi.first.wpilibj.DigitalOutput;
-/**
- * Class to control a simulated digital input or output.
- */
+/** Class to control a simulated digital input or output. */
public class DIOSim {
private final int m_index;
@@ -45,61 +40,162 @@
m_index = channel;
}
+ /**
+ * Register a callback to be run when this DIO is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DIODataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DIODataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check whether this DIO has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return DIODataJNI.getInitialized(m_index);
}
+
+ /**
+ * Define whether this DIO has been initialized.
+ *
+ * @param initialized whether this object is initialized
+ */
public void setInitialized(boolean initialized) {
DIODataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback to be run whenever the DIO value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerValueCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DIODataJNI.registerValueCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DIODataJNI::cancelValueCallback);
}
+
+ /**
+ * Read the value of the DIO port.
+ *
+ * @return the DIO value
+ */
public boolean getValue() {
return DIODataJNI.getValue(m_index);
}
+
+ /**
+ * Change the DIO value.
+ *
+ * @param value the new value
+ */
public void setValue(boolean value) {
DIODataJNI.setValue(m_index, value);
}
+ /**
+ * Register a callback to be run whenever the pulse length changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerPulseLengthCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DIODataJNI.registerPulseLengthCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DIODataJNI::cancelPulseLengthCallback);
}
+
+ /**
+ * Read the pulse length.
+ *
+ * @return the pulse length of this DIO port
+ */
public double getPulseLength() {
return DIODataJNI.getPulseLength(m_index);
}
+
+ /**
+ * Change the pulse length of this DIO port.
+ *
+ * @param pulseLength the new pulse length
+ */
public void setPulseLength(double pulseLength) {
DIODataJNI.setPulseLength(m_index, pulseLength);
}
+ /**
+ * Register a callback to be run whenever this DIO changes to be an input.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerIsInputCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DIODataJNI.registerIsInputCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DIODataJNI::cancelIsInputCallback);
}
+
+ /**
+ * Check whether this DIO port is currently an Input.
+ *
+ * @return true if Input
+ */
public boolean getIsInput() {
return DIODataJNI.getIsInput(m_index);
}
+
+ /**
+ * Define whether this DIO port is an Input.
+ *
+ * @param isInput whether this DIO should be an Input
+ */
public void setIsInput(boolean isInput) {
DIODataJNI.setIsInput(m_index, isInput);
}
+ /**
+ * Register a callback to be run whenever the filter index changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerFilterIndexCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DIODataJNI.registerFilterIndexCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DIODataJNI::cancelFilterIndexCallback);
}
+
+ /**
+ * Read the filter index.
+ *
+ * @return the filter index of this DIO port
+ */
public int getFilterIndex() {
return DIODataJNI.getFilterIndex(m_index);
}
+
+ /**
+ * Change the filter index of this DIO port.
+ *
+ * @param filterIndex the new filter index
+ */
public void setFilterIndex(int filterIndex) {
DIODataJNI.setFilterIndex(m_index, filterIndex);
}
+ /** Reset all simulation data of this object. */
public void resetData() {
DIODataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DifferentialDrivetrainSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DifferentialDrivetrainSim.java
index ab3d003..b123eac 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DifferentialDrivetrainSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DifferentialDrivetrainSim.java
@@ -1,173 +1,292 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import edu.wpi.first.wpilibj.geometry.Pose2d;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
-import edu.wpi.first.wpilibj.system.LinearSystem;
-import edu.wpi.first.wpilibj.system.RungeKutta;
-import edu.wpi.first.wpilibj.system.plant.DCMotor;
-import edu.wpi.first.wpilibj.system.plant.LinearSystemId;
-import edu.wpi.first.wpilibj.util.Units;
-import edu.wpi.first.wpiutil.math.Matrix;
-import edu.wpi.first.wpiutil.math.Nat;
-import edu.wpi.first.wpiutil.math.VecBuilder;
-import edu.wpi.first.wpiutil.math.numbers.N1;
-import edu.wpi.first.wpiutil.math.numbers.N2;
-import edu.wpi.first.wpiutil.math.numbers.N7;
+import edu.wpi.first.math.Matrix;
+import edu.wpi.first.math.Nat;
+import edu.wpi.first.math.StateSpaceUtil;
+import edu.wpi.first.math.VecBuilder;
+import edu.wpi.first.math.geometry.Pose2d;
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.math.numbers.N1;
+import edu.wpi.first.math.numbers.N2;
+import edu.wpi.first.math.numbers.N7;
+import edu.wpi.first.math.system.LinearSystem;
+import edu.wpi.first.math.system.NumericalIntegration;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.math.system.plant.LinearSystemId;
+import edu.wpi.first.math.util.Units;
+import edu.wpi.first.wpilibj.RobotController;
/**
- * This class simulates the state of the drivetrain. In simulationPeriodic, users should first set inputs from motors with
- * {@link #setInputs(double, double)}, call {@link #update(double)} to update the simulation,
- * and set estimated encoder and gyro positions, as well as estimated odometry pose. Teams can use {@link edu.wpi.first.wpilibj.simulation.Field2d} to
- * visualize their robot on the Sim GUI's field.
+ * This class simulates the state of the drivetrain. In simulationPeriodic, users should first set
+ * inputs from motors with {@link #setInputs(double, double)}, call {@link #update(double)} to
+ * update the simulation, and set estimated encoder and gyro positions, as well as estimated
+ * odometry pose. Teams can use {@link edu.wpi.first.wpilibj.smartdashboard.Field2d} to visualize
+ * their robot on the Sim GUI's field.
*
- * <p>Our state-space system is:
+ * <p>Our state-space system is:
*
- * <p>x = [[x, y, theta, vel_l, vel_r, dist_l, dist_r, voltError_l, voltError_r, headingError]]^T
- * in the field coordinate system (dist_* are wheel distances.)
+ * <p>x = [[x, y, theta, vel_l, vel_r, dist_l, dist_r]]áµ€ in the field coordinate system (dist_* are
+ * wheel distances.)
*
- * <p>u = [[voltage_l, voltage_r]]^T This is typically the control input of the last timestep
- * from a LTVDiffDriveController.
+ * <p>u = [[voltage_l, voltage_r]]áµ€ This is typically the control input of the last timestep from a
+ * LTVDiffDriveController.
*
- * <p>y = [[x, y, theta]]^T from a global measurement source(ex. vision),
- * or y = [[dist_l, dist_r, theta]] from encoders and gyro.
- *
+ * <p>y = x
*/
public class DifferentialDrivetrainSim {
private final DCMotor m_motor;
private final double m_originalGearing;
+ private final Matrix<N7, N1> m_measurementStdDevs;
private double m_currentGearing;
private final double m_wheelRadiusMeters;
+
@SuppressWarnings("MemberName")
private Matrix<N2, N1> m_u;
+
@SuppressWarnings("MemberName")
private Matrix<N7, N1> m_x;
+ @SuppressWarnings("MemberName")
+ private Matrix<N7, N1> m_y;
+
private final double m_rb;
private final LinearSystem<N2, N2, N2> m_plant;
/**
* Create a SimDrivetrain.
*
- * @param driveMotor A {@link DCMotor} representing the left side of the drivetrain.
- * @param gearing The gearing on the drive between motor and wheel, as output over input.
- * This must be the same ratio as the ratio used to identify or
- * create the drivetrainPlant.
- * @param jKgMetersSquared The moment of inertia of the drivetrain about its center.
- * @param massKg The mass of the drivebase.
+ * @param driveMotor A {@link DCMotor} representing the left side of the drivetrain.
+ * @param gearing The gearing ratio between motor and wheel, as output over input. This must be
+ * the same ratio as the ratio used to identify or create the drivetrainPlant.
+ * @param jKgMetersSquared The moment of inertia of the drivetrain about its center.
+ * @param massKg The mass of the drivebase.
* @param wheelRadiusMeters The radius of the wheels on the drivetrain.
- * @param trackWidthMeters The robot's track width, or distance between left and right wheels.
+ * @param trackWidthMeters The robot's track width, or distance between left and right wheels.
+ * @param measurementStdDevs Standard deviations for measurements, in the form [x, y, heading,
+ * left velocity, right velocity, left distance, right distance]áµ€. Can be null if no noise is
+ * desired. Gyro standard deviations of 0.0001 radians, velocity standard deviations of 0.05
+ * m/s, and position measurement standard deviations of 0.005 meters are a reasonable starting
+ * point.
*/
- public DifferentialDrivetrainSim(DCMotor driveMotor, double gearing,
- double jKgMetersSquared, double massKg,
- double wheelRadiusMeters, double trackWidthMeters) {
- this(LinearSystemId.createDrivetrainVelocitySystem(driveMotor, massKg, wheelRadiusMeters,
- trackWidthMeters / 2.0, jKgMetersSquared, gearing),
- driveMotor, gearing, trackWidthMeters, wheelRadiusMeters);
+ @SuppressWarnings("ParameterName")
+ public DifferentialDrivetrainSim(
+ DCMotor driveMotor,
+ double gearing,
+ double jKgMetersSquared,
+ double massKg,
+ double wheelRadiusMeters,
+ double trackWidthMeters,
+ Matrix<N7, N1> measurementStdDevs) {
+ this(
+ LinearSystemId.createDrivetrainVelocitySystem(
+ driveMotor,
+ massKg,
+ wheelRadiusMeters,
+ trackWidthMeters / 2.0,
+ jKgMetersSquared,
+ gearing),
+ driveMotor,
+ gearing,
+ trackWidthMeters,
+ wheelRadiusMeters,
+ measurementStdDevs);
}
/**
- * Create a SimDrivetrain
- * .
- * @param drivetrainPlant The {@link LinearSystem} representing the robot's drivetrain. This
- * system can be created with {@link edu.wpi.first.wpilibj.system.plant.LinearSystemId#createDrivetrainVelocitySystem(DCMotor, double, double, double, double, double)}
- * or {@link edu.wpi.first.wpilibj.system.plant.LinearSystemId#identifyDrivetrainSystem(double, double, double, double)}.
- * @param driveMotor A {@link DCMotor} representing the drivetrain.
- * @param gearing The gearingRatio ratio of the robot, as output over input.
- * This must be the same ratio as the ratio used to identify or
- * create the drivetrainPlant.
- * @param trackWidthMeters The distance between the two sides of the drivetrian. Can be
- * found with frc-characterization.
+ * Create a SimDrivetrain .
+ *
+ * @param drivetrainPlant The {@link LinearSystem} representing the robot's drivetrain. This
+ * system can be created with {@link
+ * edu.wpi.first.math.system.plant.LinearSystemId#createDrivetrainVelocitySystem(DCMotor,
+ * double, double, double, double, double)} or {@link
+ * edu.wpi.first.math.system.plant.LinearSystemId#identifyDrivetrainSystem(double, double,
+ * double, double)}.
+ * @param driveMotor A {@link DCMotor} representing the drivetrain.
+ * @param gearing The gearingRatio ratio of the robot, as output over input. This must be the same
+ * ratio as the ratio used to identify or create the drivetrainPlant.
+ * @param trackWidthMeters The distance between the two sides of the drivetrian. Can be found with
+ * SysId.
* @param wheelRadiusMeters The radius of the wheels on the drivetrain, in meters.
+ * @param measurementStdDevs Standard deviations for measurements, in the form [x, y, heading,
+ * left velocity, right velocity, left distance, right distance]áµ€. Can be null if no noise is
+ * desired. Gyro standard deviations of 0.0001 radians, velocity standard deviations of 0.05
+ * m/s, and position measurement standard deviations of 0.005 meters are a reasonable starting
+ * point.
*/
- public DifferentialDrivetrainSim(LinearSystem<N2, N2, N2> drivetrainPlant,
- DCMotor driveMotor, double gearing,
- double trackWidthMeters,
- double wheelRadiusMeters) {
+ public DifferentialDrivetrainSim(
+ LinearSystem<N2, N2, N2> drivetrainPlant,
+ DCMotor driveMotor,
+ double gearing,
+ double trackWidthMeters,
+ double wheelRadiusMeters,
+ Matrix<N7, N1> measurementStdDevs) {
this.m_plant = drivetrainPlant;
this.m_rb = trackWidthMeters / 2.0;
this.m_motor = driveMotor;
this.m_originalGearing = gearing;
+ this.m_measurementStdDevs = measurementStdDevs;
m_wheelRadiusMeters = wheelRadiusMeters;
m_currentGearing = m_originalGearing;
m_x = new Matrix<>(Nat.N7(), Nat.N1());
m_u = VecBuilder.fill(0, 0);
+ m_y = new Matrix<>(Nat.N7(), Nat.N1());
}
/**
- * Sets the applied voltage to the drivetrain. Note that positive voltage must make that
- * side of the drivetrain travel forward (+X).
+ * Sets the applied voltage to the drivetrain. Note that positive voltage must make that side of
+ * the drivetrain travel forward (+X).
*
- * @param leftVoltageVolts The left voltage.
+ * @param leftVoltageVolts The left voltage.
* @param rightVoltageVolts The right voltage.
*/
public void setInputs(double leftVoltageVolts, double rightVoltageVolts) {
- m_u = VecBuilder.fill(leftVoltageVolts, rightVoltageVolts);
- }
-
- @SuppressWarnings("LocalVariableName")
- public void update(double dtSeconds) {
-
- // Update state estimate with RK4
- m_x = RungeKutta.rungeKutta(this::getDynamics, m_x, m_u, dtSeconds);
- }
-
- public double getState(State state) {
- return m_x.get(state.value, 0);
+ m_u = clampInput(VecBuilder.fill(leftVoltageVolts, rightVoltageVolts));
}
/**
- * Returns the full simulated state of the drivetrain.
+ * Update the drivetrain states with the current time difference.
+ *
+ * @param dtSeconds the time difference
*/
- public Matrix<N7, N1> getState() {
+ @SuppressWarnings("LocalVariableName")
+ public void update(double dtSeconds) {
+ // Update state estimate with RK4
+ m_x = NumericalIntegration.rk4(this::getDynamics, m_x, m_u, dtSeconds);
+ m_y = m_x;
+ if (m_measurementStdDevs != null) {
+ m_y = m_y.plus(StateSpaceUtil.makeWhiteNoiseVector(m_measurementStdDevs));
+ }
+ }
+
+ /** Returns the full simulated state of the drivetrain. */
+ Matrix<N7, N1> getState() {
return m_x;
}
/**
+ * Get one of the drivetrain states.
+ *
+ * @param state the state to get
+ * @return the state
+ */
+ double getState(State state) {
+ return m_x.get(state.value, 0);
+ }
+
+ private double getOutput(State output) {
+ return m_y.get(output.value, 0);
+ }
+
+ /**
* Returns the direction the robot is pointing.
*
- * <p>Note that this angle is counterclockwise-positive, while most gyros are
- * clockwise positive.
+ * <p>Note that this angle is counterclockwise-positive, while most gyros are clockwise positive.
+ *
+ * @return The direction the robot is pointing.
*/
public Rotation2d getHeading() {
- return new Rotation2d(getState(State.kHeading));
+ return new Rotation2d(getOutput(State.kHeading));
}
/**
* Returns the current pose.
+ *
+ * @return The current pose.
*/
public Pose2d getPose() {
- return new Pose2d(m_x.get(0, 0),
- m_x.get(1, 0),
- new Rotation2d(m_x.get(2, 0)));
+ return new Pose2d(getOutput(State.kX), getOutput(State.kY), getHeading());
}
+ /**
+ * Get the right encoder position in meters.
+ *
+ * @return The encoder position.
+ */
+ public double getRightPositionMeters() {
+ return getOutput(State.kRightPosition);
+ }
+
+ /**
+ * Get the right encoder velocity in meters per second.
+ *
+ * @return The encoder velocity.
+ */
+ public double getRightVelocityMetersPerSecond() {
+ return getOutput(State.kRightVelocity);
+ }
+
+ /**
+ * Get the left encoder position in meters.
+ *
+ * @return The encoder position.
+ */
+ public double getLeftPositionMeters() {
+ return getOutput(State.kLeftPosition);
+ }
+
+ /**
+ * Get the left encoder velocity in meters per second.
+ *
+ * @return The encoder velocity.
+ */
+ public double getLeftVelocityMetersPerSecond() {
+ return getOutput(State.kLeftVelocity);
+ }
+
+ /**
+ * Get the current draw of the left side of the drivetrain.
+ *
+ * @return the drivetrain's left side current draw, in amps
+ */
+ public double getLeftCurrentDrawAmps() {
+ var loadIleft =
+ m_motor.getCurrent(
+ getState(State.kLeftVelocity) * m_currentGearing / m_wheelRadiusMeters,
+ m_u.get(0, 0))
+ * Math.signum(m_u.get(0, 0));
+ return loadIleft;
+ }
+
+ /**
+ * Get the current draw of the right side of the drivetrain.
+ *
+ * @return the drivetrain's right side current draw, in amps
+ */
+ public double getRightCurrentDrawAmps() {
+ var loadIright =
+ m_motor.getCurrent(
+ getState(State.kRightVelocity) * m_currentGearing / m_wheelRadiusMeters,
+ m_u.get(1, 0))
+ * Math.signum(m_u.get(1, 0));
+
+ return loadIright;
+ }
+
+ /**
+ * Get the current draw of the drivetrain.
+ *
+ * @return the current draw, in amps
+ */
public double getCurrentDrawAmps() {
- var loadIleft = m_motor.getCurrent(
- getState(State.kLeftVelocity) * m_currentGearing / m_wheelRadiusMeters,
- m_u.get(0, 0)) * Math.signum(m_u.get(0, 0));
-
- var loadIright = m_motor.getCurrent(
- getState(State.kRightVelocity) * m_currentGearing / m_wheelRadiusMeters,
- m_u.get(1, 0)) * Math.signum(m_u.get(1, 0));
-
- return loadIleft + loadIright;
+ return getLeftCurrentDrawAmps() + getRightCurrentDrawAmps();
}
+ /**
+ * Get the drivetrain gearing.
+ *
+ * @return the gearing ration
+ */
public double getCurrentGearing() {
return m_currentGearing;
}
/**
- * Sets the gearing reduction on the drivetrain. This is commonly used for
- * shifting drivetrains.
+ * Sets the gearing reduction on the drivetrain. This is commonly used for shifting drivetrains.
*
* @param newGearRatio The new gear ratio, as output over input.
*/
@@ -197,9 +316,8 @@
m_x.set(State.kRightPosition.value, 0, 0);
}
- @SuppressWarnings({"DuplicatedCode", "LocalVariableName"})
+ @SuppressWarnings({"DuplicatedCode", "LocalVariableName", "ParameterName"})
protected Matrix<N7, N1> getDynamics(Matrix<N7, N1> x, Matrix<N2, N1> u) {
-
// Because G can be factored out of B, we can divide by the old ratio and multiply
// by the new ratio to get a new drivetrain model.
var B = new Matrix<>(Nat.N4(), Nat.N2());
@@ -208,8 +326,14 @@
// Because G^2 can be factored out of A, we can divide by the old ratio squared and multiply
// by the new ratio squared to get a new drivetrain model.
var A = new Matrix<>(Nat.N4(), Nat.N4());
- A.assignBlock(0, 0, m_plant.getA().times((this.m_currentGearing * this.m_currentGearing)
- / (this.m_originalGearing * this.m_originalGearing)));
+ A.assignBlock(
+ 0,
+ 0,
+ m_plant
+ .getA()
+ .times(
+ (this.m_currentGearing * this.m_currentGearing)
+ / (this.m_originalGearing * this.m_originalGearing)));
A.assignBlock(2, 0, Matrix.eye(Nat.N2()));
@@ -218,16 +342,29 @@
var xdot = new Matrix<>(Nat.N7(), Nat.N1());
xdot.set(0, 0, v * Math.cos(x.get(State.kHeading.value, 0)));
xdot.set(1, 0, v * Math.sin(x.get(State.kHeading.value, 0)));
- xdot.set(2, 0, (x.get(State.kRightVelocity.value, 0)
- - x.get(State.kLeftVelocity.value, 0)) / (2.0 * m_rb));
- xdot.assignBlock(3, 0,
- A.times(x.block(Nat.N4(), Nat.N1(), 3, 0))
- .plus(B.times(u)));
+ xdot.set(
+ 2,
+ 0,
+ (x.get(State.kRightVelocity.value, 0) - x.get(State.kLeftVelocity.value, 0))
+ / (2.0 * m_rb));
+ xdot.assignBlock(3, 0, A.times(x.block(Nat.N4(), Nat.N1(), 3, 0)).plus(B.times(u)));
return xdot;
}
- public enum State {
+ /**
+ * Clamp the input vector such that no element exceeds the battery voltage. If any does, the
+ * relative magnitudes of the input will be maintained.
+ *
+ * @param u The input vector.
+ * @return The normalized input.
+ */
+ protected Matrix<N2, N1> clampInput(Matrix<N2, N1> u) {
+ return StateSpaceUtil.normalizeInputVector(u, RobotController.getBatteryVoltage());
+ }
+
+ /** Represents the different states of the drivetrain. */
+ enum State {
kX(0),
kY(1),
kHeading(2),
@@ -239,18 +376,15 @@
@SuppressWarnings("MemberName")
public final int value;
+ @SuppressWarnings("ParameterName")
State(int i) {
this.value = i;
}
}
/**
- * Represents a gearing option of the Toughbox mini.
- * 12.75:1 -- 14:50 and 14:50
- * 10.71:1 -- 14:50 and 16:48
- * 8.45:1 -- 14:50 and 19:45
- * 7.31:1 -- 14:50 and 21:43
- * 5.95:1 -- 14:50 and 24:40
+ * Represents a gearing option of the Toughbox mini. 12.75:1 -- 14:50 and 14:50 10.71:1 -- 14:50
+ * and 16:48 8.45:1 -- 14:50 and 19:45 7.31:1 -- 14:50 and 21:43 5.95:1 -- 14:50 and 24:40
*/
public enum KitbotGearing {
k12p75(12.75),
@@ -262,11 +396,13 @@
@SuppressWarnings("MemberName")
public final double value;
+ @SuppressWarnings("ParameterName")
KitbotGearing(double i) {
this.value = i;
}
}
+ /** Represents common motor layouts of the kit drivetrain. */
public enum KitbotMotor {
kSingleCIMPerSide(DCMotor.getCIM(1)),
kDualCIMPerSide(DCMotor.getCIM(2)),
@@ -276,19 +412,29 @@
@SuppressWarnings("MemberName")
public final DCMotor value;
+ @SuppressWarnings("ParameterName")
KitbotMotor(DCMotor i) {
this.value = i;
}
}
+ /** Represents common wheel sizes of the kit drivetrain. */
public enum KitbotWheelSize {
+ kSixInch(Units.inchesToMeters(6)),
+ kEightInch(Units.inchesToMeters(8)),
+ kTenInch(Units.inchesToMeters(10)),
+
+ @Deprecated
SixInch(Units.inchesToMeters(6)),
+ @Deprecated
EightInch(Units.inchesToMeters(8)),
+ @Deprecated
TenInch(Units.inchesToMeters(10));
@SuppressWarnings("MemberName")
public final double value;
+ @SuppressWarnings("ParameterName")
KitbotWheelSize(double i) {
this.value = i;
}
@@ -297,32 +443,59 @@
/**
* Create a sim for the standard FRC kitbot.
*
- * @param motor The motors installed in the bot.
- * @param gearing The gearing reduction used.
+ * @param motor The motors installed in the bot.
+ * @param gearing The gearing reduction used.
* @param wheelSize The wheel size.
+ * @param measurementStdDevs Standard deviations for measurements, in the form [x, y, heading,
+ * left velocity, right velocity, left distance, right distance]áµ€. Can be null if no noise is
+ * desired. Gyro standard deviations of 0.0001 radians, velocity standard deviations of 0.05
+ * m/s, and position measurement standard deviations of 0.005 meters are a reasonable starting
+ * point.
+ * @return A sim for the standard FRC kitbot.
*/
- public static DifferentialDrivetrainSim createKitbotSim(KitbotMotor motor, KitbotGearing gearing,
- KitbotWheelSize wheelSize) {
+ public static DifferentialDrivetrainSim createKitbotSim(
+ KitbotMotor motor,
+ KitbotGearing gearing,
+ KitbotWheelSize wheelSize,
+ Matrix<N7, N1> measurementStdDevs) {
// MOI estimation -- note that I = m r^2 for point masses
var batteryMoi = 12.5 / 2.2 * Math.pow(Units.inchesToMeters(10), 2);
- var gearboxMoi = (2.8 /* CIM motor */ * 2 / 2.2 + 2.0 /* Toughbox Mini- ish */)
- * Math.pow(Units.inchesToMeters(26.0 / 2.0), 2);
+ var gearboxMoi =
+ (2.8 /* CIM motor */ * 2 / 2.2 + 2.0 /* Toughbox Mini- ish */)
+ * Math.pow(Units.inchesToMeters(26.0 / 2.0), 2);
- return createKitbotSim(motor, gearing, wheelSize, batteryMoi + gearboxMoi);
+ return createKitbotSim(motor, gearing, wheelSize, batteryMoi + gearboxMoi, measurementStdDevs);
}
/**
* Create a sim for the standard FRC kitbot.
*
- * @param motor The motors installed in the bot.
- * @param gearing The gearing reduction used.
- * @param wheelSize The wheel size.
+ * @param motor The motors installed in the bot.
+ * @param gearing The gearing reduction used.
+ * @param wheelSize The wheel size.
* @param jKgMetersSquared The moment of inertia of the drivebase. This can be calculated using
- * frc-characterization.
+ * SysId.
+ * @param measurementStdDevs Standard deviations for measurements, in the form [x, y, heading,
+ * left velocity, right velocity, left distance, right distance]áµ€. Can be null if no noise is
+ * desired. Gyro standard deviations of 0.0001 radians, velocity standard deviations of 0.05
+ * m/s, and position measurement standard deviations of 0.005 meters are a reasonable starting
+ * point.
+ * @return A sim for the standard FRC kitbot.
*/
- public static DifferentialDrivetrainSim createKitbotSim(KitbotMotor motor, KitbotGearing gearing,
- KitbotWheelSize wheelSize, double jKgMetersSquared) {
- return new DifferentialDrivetrainSim(motor.value, gearing.value, jKgMetersSquared, 25 / 2.2,
- wheelSize.value / 2.0, Units.inchesToMeters(26));
+ @SuppressWarnings("ParameterName")
+ public static DifferentialDrivetrainSim createKitbotSim(
+ KitbotMotor motor,
+ KitbotGearing gearing,
+ KitbotWheelSize wheelSize,
+ double jKgMetersSquared,
+ Matrix<N7, N1> measurementStdDevs) {
+ return new DifferentialDrivetrainSim(
+ motor.value,
+ gearing.value,
+ jKgMetersSquared,
+ Units.lbsToKilograms(60),
+ wheelSize.value / 2.0,
+ Units.inchesToMeters(26),
+ measurementStdDevs);
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DigitalPWMSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DigitalPWMSim.java
index db942eb..f18f092 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DigitalPWMSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DigitalPWMSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -15,8 +12,8 @@
/**
* Class to control a simulated digital PWM output.
*
- * <p>This is for duty cycle PWM outputs on a DigitalOutput, not for the servo
- * style PWM outputs on a PWM channel.
+ * <p>This is for duty cycle PWM outputs on a DigitalOutput, not for the servo style PWM outputs on
+ * a PWM channel.
*/
public class DigitalPWMSim {
private final int m_index;
@@ -50,8 +47,8 @@
}
/**
- * Creates an DigitalPWMSim for a simulated index.
- * The index is incremented for each simulated DigitalPWM.
+ * Creates an DigitalPWMSim for a simulated index. The index is incremented for each simulated
+ * DigitalPWM.
*
* @param index simulator index
* @return Simulated object
@@ -60,39 +57,100 @@
return new DigitalPWMSim(index);
}
+ /**
+ * Register a callback to be run when this PWM output is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DigitalPWMDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DigitalPWMDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check whether this PWM output has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return DigitalPWMDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Define whether this PWM output has been initialized.
+ *
+ * @param initialized whether this object is initialized
+ */
public void setInitialized(boolean initialized) {
DigitalPWMDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback to be run whenever the duty cycle value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerDutyCycleCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DigitalPWMDataJNI.registerDutyCycleCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DigitalPWMDataJNI::cancelDutyCycleCallback);
}
+
+ /**
+ * Read the duty cycle value.
+ *
+ * @return the duty cycle value of this PWM output
+ */
public double getDutyCycle() {
return DigitalPWMDataJNI.getDutyCycle(m_index);
}
+
+ /**
+ * Set the duty cycle value of this PWM output.
+ *
+ * @param dutyCycle the new value
+ */
public void setDutyCycle(double dutyCycle) {
DigitalPWMDataJNI.setDutyCycle(m_index, dutyCycle);
}
+ /**
+ * Register a callback to be run whenever the pin changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerPinCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DigitalPWMDataJNI.registerPinCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DigitalPWMDataJNI::cancelPinCallback);
}
+
+ /**
+ * Check the pin number.
+ *
+ * @return the pin number
+ */
public int getPin() {
return DigitalPWMDataJNI.getPin(m_index);
}
+
+ /**
+ * Change the pin number.
+ *
+ * @param pin the new pin number
+ */
public void setPin(int pin) {
DigitalPWMDataJNI.setPin(m_index, pin);
}
+ /** Reset all simulation data. */
public void resetData() {
DigitalPWMDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DriverStationSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DriverStationSim.java
index 40b1017..f6da659 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DriverStationSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DriverStationSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -12,81 +9,223 @@
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.wpilibj.DriverStation;
-/**
- * Class to control a simulated driver station.
- */
-@SuppressWarnings({"PMD.UseUtilityClass", "PMD.GodClass", "PMD.ExcessivePublicCount"})
-public class DriverStationSim {
- public static CallbackStore registerEnabledCallback(NotifyCallback callback, boolean initialNotify) {
+/** Class to control a simulated driver station. */
+public final class DriverStationSim {
+ private DriverStationSim() {
+ throw new UnsupportedOperationException("This is a utility class!");
+ }
+
+ /**
+ * Register a callback on whether the DS is enabled.
+ *
+ * @param callback the callback that will be called whenever the enabled state is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerEnabledCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = DriverStationDataJNI.registerEnabledCallback(callback, initialNotify);
return new CallbackStore(uid, DriverStationDataJNI::cancelEnabledCallback);
}
+
+ /**
+ * Check if the DS is enabled.
+ *
+ * @return true if enabled
+ */
public static boolean getEnabled() {
return DriverStationDataJNI.getEnabled();
}
+
+ /**
+ * Change whether the DS is enabled.
+ *
+ * @param enabled the new value
+ */
public static void setEnabled(boolean enabled) {
DriverStationDataJNI.setEnabled(enabled);
}
- public static CallbackStore registerAutonomousCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on whether the DS is in autonomous mode.
+ *
+ * @param callback the callback that will be called on autonomous mode entrance/exit
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerAutonomousCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = DriverStationDataJNI.registerAutonomousCallback(callback, initialNotify);
return new CallbackStore(uid, DriverStationDataJNI::cancelAutonomousCallback);
}
+
+ /**
+ * Check if the DS is in autonomous.
+ *
+ * @return true if autonomous
+ */
public static boolean getAutonomous() {
return DriverStationDataJNI.getAutonomous();
}
+
+ /**
+ * Change whether the DS is in autonomous.
+ *
+ * @param autonomous the new value
+ */
public static void setAutonomous(boolean autonomous) {
DriverStationDataJNI.setAutonomous(autonomous);
}
+ /**
+ * Register a callback on whether the DS is in test mode.
+ *
+ * @param callback the callback that will be called whenever the test mode is entered or left
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public static CallbackStore registerTestCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DriverStationDataJNI.registerTestCallback(callback, initialNotify);
return new CallbackStore(uid, DriverStationDataJNI::cancelTestCallback);
}
+
+ /**
+ * Check if the DS is in test.
+ *
+ * @return true if test
+ */
public static boolean getTest() {
return DriverStationDataJNI.getTest();
}
+
+ /**
+ * Change whether the DS is in test.
+ *
+ * @param test the new value
+ */
public static void setTest(boolean test) {
DriverStationDataJNI.setTest(test);
}
- public static CallbackStore registerEStopCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the eStop state.
+ *
+ * @param callback the callback that will be called whenever the eStop state changes
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerEStopCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = DriverStationDataJNI.registerEStopCallback(callback, initialNotify);
return new CallbackStore(uid, DriverStationDataJNI::cancelEStopCallback);
}
+
+ /**
+ * Check if eStop has been activated.
+ *
+ * @return true if eStopped
+ */
public static boolean getEStop() {
return DriverStationDataJNI.getEStop();
}
+
+ /**
+ * Set whether eStop is active.
+ *
+ * @param eStop true to activate
+ */
+ @SuppressWarnings("ParameterName")
public static void setEStop(boolean eStop) {
DriverStationDataJNI.setEStop(eStop);
}
- public static CallbackStore registerFmsAttachedCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on whether the FMS is connected.
+ *
+ * @param callback the callback that will be called whenever the FMS connection changes
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerFmsAttachedCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = DriverStationDataJNI.registerFmsAttachedCallback(callback, initialNotify);
return new CallbackStore(uid, DriverStationDataJNI::cancelFmsAttachedCallback);
}
+
+ /**
+ * Check if the FMS is connected.
+ *
+ * @return true if FMS is connected
+ */
public static boolean getFmsAttached() {
return DriverStationDataJNI.getFmsAttached();
}
+
+ /**
+ * Change whether the FMS is connected.
+ *
+ * @param fmsAttached the new value
+ */
public static void setFmsAttached(boolean fmsAttached) {
DriverStationDataJNI.setFmsAttached(fmsAttached);
}
- public static CallbackStore registerDsAttachedCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on whether the DS is connected.
+ *
+ * @param callback the callback that will be called whenever the DS connection changes
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerDsAttachedCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = DriverStationDataJNI.registerDsAttachedCallback(callback, initialNotify);
return new CallbackStore(uid, DriverStationDataJNI::cancelDsAttachedCallback);
}
+
+ /**
+ * Check if the DS is attached.
+ *
+ * @return true if attached
+ */
public static boolean getDsAttached() {
return DriverStationDataJNI.getDsAttached();
}
+
+ /**
+ * Change whether the DS is attached.
+ *
+ * @param dsAttached the new value
+ */
public static void setDsAttached(boolean dsAttached) {
DriverStationDataJNI.setDsAttached(dsAttached);
}
- public static CallbackStore registerAllianceStationIdCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the alliance station ID.
+ *
+ * @param callback the callback that will be called whenever the alliance station changes
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerAllianceStationIdCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = DriverStationDataJNI.registerAllianceStationIdCallback(callback, initialNotify);
return new CallbackStore(uid, DriverStationDataJNI::cancelAllianceStationIdCallback);
}
+
+ /**
+ * Get the alliance station ID (color + number).
+ *
+ * @return the alliance station color and number
+ */
public static AllianceStationID getAllianceStationId() {
switch (DriverStationDataJNI.getAllianceStationId()) {
case 0:
@@ -105,6 +244,12 @@
return null;
}
}
+
+ /**
+ * Change the alliance station.
+ *
+ * @param allianceStationId the new alliance station
+ */
public static void setAllianceStationId(AllianceStationID allianceStationId) {
int allianceStation;
switch (allianceStationId) {
@@ -132,24 +277,42 @@
DriverStationDataJNI.setAllianceStationId(allianceStation);
}
- public static CallbackStore registerMatchTimeCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on match time.
+ *
+ * @param callback the callback that will be called whenever match time changes
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerMatchTimeCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = DriverStationDataJNI.registerMatchTimeCallback(callback, initialNotify);
return new CallbackStore(uid, DriverStationDataJNI::cancelMatchTimeCallback);
}
+
+ /**
+ * Get the current value of the match timer.
+ *
+ * @return the current match time
+ */
public static double getMatchTime() {
return DriverStationDataJNI.getMatchTime();
}
+
+ /**
+ * Sets the match timer.
+ *
+ * @param matchTime the new match time
+ */
public static void setMatchTime(double matchTime) {
DriverStationDataJNI.setMatchTime(matchTime);
}
- /**
- * Updates DriverStation data so that new values are visible to the user
- * program.
- */
+ /** Updates DriverStation data so that new values are visible to the user program. */
public static void notifyNewData() {
DriverStationDataJNI.notifyNewData();
- DriverStation.getInstance().waitForData();
+ DriverStation.waitForData();
}
/**
@@ -194,7 +357,7 @@
/**
* Sets the state of one joystick button. Button indexes begin at 1.
*
- * @param stick The joystick number
+ * @param stick The joystick number
* @param button The button index, beginning at 1
* @param state The state of the joystick button
*/
@@ -206,7 +369,7 @@
* Gets the value of the axis on a joystick.
*
* @param stick The joystick number
- * @param axis The analog axis number
+ * @param axis The analog axis number
* @param value The value of the axis on the joystick
*/
public static void setJoystickAxis(int stick, int axis, double value) {
@@ -367,6 +530,7 @@
DriverStationDataJNI.setReplayNumber(replayNumber);
}
+ /** Reset all simulation data for the Driver Station. */
public static void resetData() {
DriverStationDataJNI.resetData();
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DutyCycleEncoderSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DutyCycleEncoderSim.java
index 92b0883..f5c900c 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DutyCycleEncoderSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DutyCycleEncoderSim.java
@@ -1,18 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.wpilibj.DutyCycleEncoder;
-/**
- * Class to control a simulated duty cycle encoder.
- */
+/** Class to control a simulated duty cycle encoder. */
public class DutyCycleEncoderSim {
private final SimDouble m_simPosition;
private final SimDouble m_simDistancePerRotation;
@@ -23,9 +18,10 @@
* @param encoder DutyCycleEncoder to simulate
*/
public DutyCycleEncoderSim(DutyCycleEncoder encoder) {
- SimDeviceSim wrappedSimDevice = new SimDeviceSim("DutyCycleEncoder" + "[" + encoder.getFPGAIndex() + "]");
- m_simPosition = wrappedSimDevice.getDouble("Position");
- m_simDistancePerRotation = wrappedSimDevice.getDouble("DistancePerRotation");
+ SimDeviceSim wrappedSimDevice =
+ new SimDeviceSim("DutyCycle:DutyCycleEncoder" + "[" + encoder.getSourceChannel() + "]");
+ m_simPosition = wrappedSimDevice.getDouble("position");
+ m_simDistancePerRotation = wrappedSimDevice.getDouble("distance_per_rot");
}
/**
@@ -39,6 +35,8 @@
/**
* Set the position.
+ *
+ * @param distance The position.
*/
public void setDistance(double distance) {
m_simPosition.set(distance / m_simDistancePerRotation.get());
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DutyCycleSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DutyCycleSim.java
index 726e08c..e893954 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DutyCycleSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/DutyCycleSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -12,9 +9,7 @@
import edu.wpi.first.wpilibj.DutyCycle;
import java.util.NoSuchElementException;
-/**
- * Class to control a simulated duty cycle digital input.
- */
+/** Class to control a simulated duty cycle digital input. */
public class DutyCycleSim {
private final int m_index;
@@ -47,8 +42,8 @@
}
/**
- * Creates a DutyCycleSim for a simulated index.
- * The index is incremented for each simulated DutyCycle.
+ * Creates a DutyCycleSim for a simulated index. The index is incremented for each simulated
+ * DutyCycle.
*
* @param index simulator index
* @return Simulated object
@@ -57,36 +52,101 @@
return new DutyCycleSim(index);
}
+ /**
+ * Register a callback to be run when this duty cycle input is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DutyCycleDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DutyCycleDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check whether this duty cycle input has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return DutyCycleDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Define whether this duty cycle input has been initialized.
+ *
+ * @param initialized whether this object is initialized
+ */
public void setInitialized(boolean initialized) {
DutyCycleDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback to be run whenever the frequency changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerFrequencyCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DutyCycleDataJNI.registerFrequencyCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DutyCycleDataJNI::cancelFrequencyCallback);
}
+
+ /**
+ * Measure the frequency.
+ *
+ * @return the duty cycle frequency
+ */
public int getFrequency() {
return DutyCycleDataJNI.getFrequency(m_index);
}
+
+ /**
+ * Change the duty cycle frequency.
+ *
+ * @param frequency the new frequency
+ */
public void setFrequency(int frequency) {
DutyCycleDataJNI.setFrequency(m_index, frequency);
}
+ /**
+ * Register a callback to be run whenever the output changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerOutputCallback(NotifyCallback callback, boolean initialNotify) {
int uid = DutyCycleDataJNI.registerOutputCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, DutyCycleDataJNI::cancelOutputCallback);
}
+
+ /**
+ * Measure the output from this duty cycle port.
+ *
+ * @return the output value
+ */
public double getOutput() {
return DutyCycleDataJNI.getOutput(m_index);
}
+
+ /**
+ * Change the duty cycle output.
+ *
+ * @param output the new output value
+ */
public void setOutput(double output) {
DutyCycleDataJNI.setOutput(m_index, output);
}
+
+ /** Reset all simulation data for the duty cycle output. */
+ public void resetData() {
+ DutyCycleDataJNI.resetData(m_index);
+ }
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ElevatorSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ElevatorSim.java
index 1610089..ecd2379 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ElevatorSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/ElevatorSim.java
@@ -1,24 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import edu.wpi.first.wpilibj.system.LinearSystem;
-import edu.wpi.first.wpilibj.system.RungeKutta;
-import edu.wpi.first.wpilibj.system.plant.DCMotor;
-import edu.wpi.first.wpilibj.system.plant.LinearSystemId;
-import edu.wpi.first.wpiutil.math.Matrix;
-import edu.wpi.first.wpiutil.math.VecBuilder;
-import edu.wpi.first.wpiutil.math.numbers.N1;
-import edu.wpi.first.wpiutil.math.numbers.N2;
+import edu.wpi.first.math.Matrix;
+import edu.wpi.first.math.VecBuilder;
+import edu.wpi.first.math.numbers.N1;
+import edu.wpi.first.math.numbers.N2;
+import edu.wpi.first.math.system.LinearSystem;
+import edu.wpi.first.math.system.NumericalIntegration;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.math.system.plant.LinearSystemId;
-/**
- * Represents a simulated elevator mechanism.
- */
+/** Represents a simulated elevator mechanism. */
public class ElevatorSim extends LinearSystemSim<N2, N1, N1> {
// Gearbox for the elevator.
private final DCMotor m_gearbox;
@@ -38,32 +33,42 @@
/**
* Creates a simulated elevator mechanism.
*
- * @param plant The linear system that represents the elevator.
- * @param gearbox The type of and number of motors in the elevator gearbox.
- * @param gearing The gearing of the elevator (numbers greater than 1 represent reductions).
+ * @param plant The linear system that represents the elevator.
+ * @param gearbox The type of and number of motors in the elevator gearbox.
+ * @param gearing The gearing of the elevator (numbers greater than 1 represent reductions).
* @param drumRadiusMeters The radius of the drum that the elevator spool is wrapped around.
- * @param minHeightMeters The min allowable height of the elevator.
- * @param maxHeightMeters The max allowable height of the elevator.
+ * @param minHeightMeters The min allowable height of the elevator.
+ * @param maxHeightMeters The max allowable height of the elevator.
*/
- public ElevatorSim(LinearSystem<N2, N1, N1> plant, DCMotor gearbox, double gearing,
- double drumRadiusMeters, double minHeightMeters, double maxHeightMeters) {
+ public ElevatorSim(
+ LinearSystem<N2, N1, N1> plant,
+ DCMotor gearbox,
+ double gearing,
+ double drumRadiusMeters,
+ double minHeightMeters,
+ double maxHeightMeters) {
this(plant, gearbox, gearing, drumRadiusMeters, minHeightMeters, maxHeightMeters, null);
}
/**
* Creates a simulated elevator mechanism.
*
- * @param plant The linear system that represents the elevator.
- * @param gearbox The type of and number of motors in the elevator gearbox.
- * @param gearing The gearing of the elevator (numbers greater than 1 represent reductions).
- * @param drumRadiusMeters The radius of the drum that the elevator spool is wrapped around.
- * @param minHeightMeters The min allowable height of the elevator.
- * @param maxHeightMeters The max allowable height of the elevator.
+ * @param plant The linear system that represents the elevator.
+ * @param gearbox The type of and number of motors in the elevator gearbox.
+ * @param gearing The gearing of the elevator (numbers greater than 1 represent reductions).
+ * @param drumRadiusMeters The radius of the drum that the elevator spool is wrapped around.
+ * @param minHeightMeters The min allowable height of the elevator.
+ * @param maxHeightMeters The max allowable height of the elevator.
* @param measurementStdDevs The standard deviations of the measurements.
*/
- public ElevatorSim(LinearSystem<N2, N1, N1> plant, DCMotor gearbox, double gearing,
- double drumRadiusMeters, double minHeightMeters, double maxHeightMeters,
- Matrix<N1, N1> measurementStdDevs) {
+ public ElevatorSim(
+ LinearSystem<N2, N1, N1> plant,
+ DCMotor gearbox,
+ double gearing,
+ double drumRadiusMeters,
+ double minHeightMeters,
+ double maxHeightMeters,
+ Matrix<N1, N1> measurementStdDevs) {
super(plant, measurementStdDevs);
m_gearbox = gearbox;
m_gearing = gearing;
@@ -75,34 +80,45 @@
/**
* Creates a simulated elevator mechanism.
*
- * @param gearbox The type of and number of motors in the elevator gearbox.
- * @param gearing The gearing of the elevator (numbers greater than 1 represent reductions).
- * @param carriageMassKg The mass of the elevator carriage.
+ * @param gearbox The type of and number of motors in the elevator gearbox.
+ * @param gearing The gearing of the elevator (numbers greater than 1 represent reductions).
+ * @param carriageMassKg The mass of the elevator carriage.
* @param drumRadiusMeters The radius of the drum that the elevator spool is wrapped around.
- * @param minHeightMeters The min allowable height of the elevator.
- * @param maxHeightMeters The max allowable height of the elevator.
+ * @param minHeightMeters The min allowable height of the elevator.
+ * @param maxHeightMeters The max allowable height of the elevator.
*/
- public ElevatorSim(DCMotor gearbox, double gearing, double carriageMassKg,
- double drumRadiusMeters, double minHeightMeters, double maxHeightMeters) {
- this(gearbox, gearing, carriageMassKg, drumRadiusMeters, minHeightMeters, maxHeightMeters,
- null);
+ public ElevatorSim(
+ DCMotor gearbox,
+ double gearing,
+ double carriageMassKg,
+ double drumRadiusMeters,
+ double minHeightMeters,
+ double maxHeightMeters) {
+ this(
+ gearbox, gearing, carriageMassKg, drumRadiusMeters, minHeightMeters, maxHeightMeters, null);
}
/**
* Creates a simulated elevator mechanism.
*
- * @param gearbox The type of and number of motors in the elevator gearbox.
- * @param gearing The gearing of the elevator (numbers greater than 1 represent reductions).
- * @param carriageMassKg The mass of the elevator carriage.
- * @param drumRadiusMeters The radius of the drum that the elevator spool is wrapped around.
- * @param minHeightMeters The min allowable height of the elevator.
- * @param maxHeightMeters The max allowable height of the elevator.
+ * @param gearbox The type of and number of motors in the elevator gearbox.
+ * @param gearing The gearing of the elevator (numbers greater than 1 represent reductions).
+ * @param carriageMassKg The mass of the elevator carriage.
+ * @param drumRadiusMeters The radius of the drum that the elevator spool is wrapped around.
+ * @param minHeightMeters The min allowable height of the elevator.
+ * @param maxHeightMeters The max allowable height of the elevator.
* @param measurementStdDevs The standard deviations of the measurements.
*/
- public ElevatorSim(DCMotor gearbox, double gearing, double carriageMassKg,
- double drumRadiusMeters, double minHeightMeters, double maxHeightMeters,
- Matrix<N1, N1> measurementStdDevs) {
- super(LinearSystemId.createElevatorSystem(gearbox, carriageMassKg, drumRadiusMeters, gearing),
+ public ElevatorSim(
+ DCMotor gearbox,
+ double gearing,
+ double carriageMassKg,
+ double drumRadiusMeters,
+ double minHeightMeters,
+ double maxHeightMeters,
+ Matrix<N1, N1> measurementStdDevs) {
+ super(
+ LinearSystemId.createElevatorSystem(gearbox, carriageMassKg, drumRadiusMeters, gearing),
measurementStdDevs);
m_gearbox = gearbox;
m_gearing = gearing;
@@ -112,23 +128,41 @@
}
/**
+ * Returns whether the elevator would hit the lower limit.
+ *
+ * @param elevatorHeightMeters The elevator height.
+ * @return Whether the elevator would hit the lower limit.
+ */
+ public boolean wouldHitLowerLimit(double elevatorHeightMeters) {
+ return elevatorHeightMeters < this.m_minHeight;
+ }
+
+ /**
+ * Returns whether the elevator would hit the upper limit.
+ *
+ * @param elevatorHeightMeters The elevator height.
+ * @return Whether the elevator would hit the upper limit.
+ */
+ public boolean wouldHitUpperLimit(double elevatorHeightMeters) {
+ return elevatorHeightMeters > this.m_maxHeight;
+ }
+
+ /**
* Returns whether the elevator has hit the lower limit.
*
- * @param x The current elevator state.
* @return Whether the elevator has hit the lower limit.
*/
- public boolean hasHitLowerLimit(Matrix<N2, N1> x) {
- return x.get(0, 0) < this.m_minHeight;
+ public boolean hasHitLowerLimit() {
+ return wouldHitLowerLimit(getPositionMeters());
}
/**
* Returns whether the elevator has hit the upper limit.
*
- * @param x The current elevator state.
* @return Whether the elevator has hit the upper limit.
*/
- public boolean hasHitUpperLimit(Matrix<N2, N1> x) {
- return x.get(0, 0) > this.m_maxHeight;
+ public boolean hasHitUpperLimit() {
+ return wouldHitUpperLimit(getPositionMeters());
}
/**
@@ -146,7 +180,7 @@
* @return The velocity of the elevator.
*/
public double getVelocityMetersPerSecond() {
- return m_x.get(0, 1);
+ return m_x.get(1, 0);
}
/**
@@ -162,7 +196,8 @@
// v = r w, so w = v/r
double motorVelocityRadPerSec = getVelocityMetersPerSecond() / m_drumRadius * m_gearing;
var appliedVoltage = m_u.get(0, 0);
- return m_gearbox.getCurrent(motorVelocityRadPerSec, appliedVoltage) * Math.signum(appliedVoltage);
+ return m_gearbox.getCurrent(motorVelocityRadPerSec, appliedVoltage)
+ * Math.signum(appliedVoltage);
}
/**
@@ -178,22 +213,28 @@
* Updates the state of the elevator.
*
* @param currentXhat The current state estimate.
- * @param u The system inputs (voltage).
- * @param dtSeconds The time difference between controller updates.
+ * @param u The system inputs (voltage).
+ * @param dtSeconds The time difference between controller updates.
*/
+ @SuppressWarnings({"ParameterName", "LambdaParameterName"})
@Override
- protected Matrix<N2, N1> updateX(Matrix<N2, N1> currentXhat,
- Matrix<N1, N1> u, double dtSeconds) {
+ protected Matrix<N2, N1> updateX(Matrix<N2, N1> currentXhat, Matrix<N1, N1> u, double dtSeconds) {
// Calculate updated x-hat from Runge-Kutta.
- var updatedXhat = RungeKutta.rungeKutta(
- (x, u_) -> (m_plant.getA().times(x)).plus(m_plant.getB().times(u_))
- .plus(VecBuilder.fill(0, -9.8)), currentXhat, u, dtSeconds);
+ var updatedXhat =
+ NumericalIntegration.rkdp(
+ (x, u_) ->
+ (m_plant.getA().times(x))
+ .plus(m_plant.getB().times(u_))
+ .plus(VecBuilder.fill(0, -9.8)),
+ currentXhat,
+ u,
+ dtSeconds);
// We check for collisions after updating x-hat.
- if (hasHitLowerLimit(updatedXhat)) {
+ if (wouldHitLowerLimit(updatedXhat.get(0, 0))) {
return VecBuilder.fill(m_minHeight, 0);
}
- if (hasHitUpperLimit(updatedXhat)) {
+ if (wouldHitUpperLimit(updatedXhat.get(0, 0))) {
return VecBuilder.fill(m_maxHeight, 0);
}
return updatedXhat;
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/EncoderSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/EncoderSim.java
index 9df5187..924ba99 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/EncoderSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/EncoderSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -12,9 +9,7 @@
import edu.wpi.first.wpilibj.Encoder;
import java.util.NoSuchElementException;
-/**
- * Class to control a simulated encoder.
- */
+/** Class to control a simulated encoder. */
public class EncoderSim {
private final int m_index;
@@ -32,8 +27,8 @@
}
/**
- * Creates an EncoderSim for a digital input channel. Encoders take two
- * channels, so either one may be specified.
+ * Creates an EncoderSim for a digital input channel. Encoders take two channels, so either one
+ * may be specified.
*
* @param channel digital input channel
* @return Simulated object
@@ -48,8 +43,8 @@
}
/**
- * Creates an EncoderSim for a simulated index.
- * The index is incremented for each simulated Encoder.
+ * Creates an EncoderSim for a simulated index. The index is incremented for each simulated
+ * Encoder.
*
* @param index simulator index
* @return Simulated object
@@ -58,110 +53,293 @@
return new EncoderSim(index);
}
+ /**
+ * Register a callback on the Initialized property of the encoder.
+ *
+ * @param callback the callback that will be called whenever the Initialized property is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = EncoderDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, EncoderDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Read the Initialized value of the encoder.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return EncoderDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Change the Initialized value of the encoder.
+ *
+ * @param initialized the new value
+ */
public void setInitialized(boolean initialized) {
EncoderDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback on the count property of the encoder.
+ *
+ * @param callback the callback that will be called whenever the count property is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerCountCallback(NotifyCallback callback, boolean initialNotify) {
int uid = EncoderDataJNI.registerCountCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, EncoderDataJNI::cancelCountCallback);
}
+
+ /**
+ * Read the count of the encoder.
+ *
+ * @return the count
+ */
public int getCount() {
return EncoderDataJNI.getCount(m_index);
}
+
+ /**
+ * Change the count of the encoder.
+ *
+ * @param count the new count
+ */
public void setCount(int count) {
EncoderDataJNI.setCount(m_index, count);
}
+ /**
+ * Register a callback on the period of the encoder.
+ *
+ * @param callback the callback that will be called whenever the period is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerPeriodCallback(NotifyCallback callback, boolean initialNotify) {
int uid = EncoderDataJNI.registerPeriodCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, EncoderDataJNI::cancelPeriodCallback);
}
+
+ /**
+ * Read the period of the encoder.
+ *
+ * @return the encoder period
+ */
public double getPeriod() {
return EncoderDataJNI.getPeriod(m_index);
}
+
+ /**
+ * Change the encoder period.
+ *
+ * @param period the new period
+ */
public void setPeriod(double period) {
EncoderDataJNI.setPeriod(m_index, period);
}
+ /**
+ * Register a callback to be called whenever the encoder is reset.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerResetCallback(NotifyCallback callback, boolean initialNotify) {
int uid = EncoderDataJNI.registerResetCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, EncoderDataJNI::cancelResetCallback);
}
+
+ /**
+ * Check if the encoder has been reset.
+ *
+ * @return true if reset
+ */
public boolean getReset() {
return EncoderDataJNI.getReset(m_index);
}
+
+ /**
+ * Change the reset property of the encoder.
+ *
+ * @param reset the new value
+ */
public void setReset(boolean reset) {
EncoderDataJNI.setReset(m_index, reset);
}
+ /**
+ * Register a callback to be run whenever the max period of the encoder is changed.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerMaxPeriodCallback(NotifyCallback callback, boolean initialNotify) {
int uid = EncoderDataJNI.registerMaxPeriodCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, EncoderDataJNI::cancelMaxPeriodCallback);
}
+
+ /**
+ * Get the max period of the encoder.
+ *
+ * @return the max period of the encoder
+ */
public double getMaxPeriod() {
return EncoderDataJNI.getMaxPeriod(m_index);
}
+
+ /**
+ * Change the max period of the encoder.
+ *
+ * @param maxPeriod the new value
+ */
public void setMaxPeriod(double maxPeriod) {
EncoderDataJNI.setMaxPeriod(m_index, maxPeriod);
}
+ /**
+ * Register a callback on the direction of the encoder.
+ *
+ * @param callback the callback that will be called whenever the direction is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerDirectionCallback(NotifyCallback callback, boolean initialNotify) {
int uid = EncoderDataJNI.registerDirectionCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, EncoderDataJNI::cancelDirectionCallback);
}
+
+ /**
+ * Get the direction of the encoder.
+ *
+ * @return the direction of the encoder
+ */
public boolean getDirection() {
return EncoderDataJNI.getDirection(m_index);
}
+
+ /**
+ * Set the direction of the encoder.
+ *
+ * @param direction the new direction
+ */
public void setDirection(boolean direction) {
EncoderDataJNI.setDirection(m_index, direction);
}
- public CallbackStore registerReverseDirectionCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the reverse direction.
+ *
+ * @param callback the callback that will be called whenever the reverse direction is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerReverseDirectionCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = EncoderDataJNI.registerReverseDirectionCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, EncoderDataJNI::cancelReverseDirectionCallback);
}
+
+ /**
+ * Get the reverse direction of the encoder.
+ *
+ * @return the reverse direction of the encoder
+ */
public boolean getReverseDirection() {
return EncoderDataJNI.getReverseDirection(m_index);
}
+
+ /**
+ * Set the reverse direction.
+ *
+ * @param reverseDirection the new value
+ */
public void setReverseDirection(boolean reverseDirection) {
EncoderDataJNI.setReverseDirection(m_index, reverseDirection);
}
- public CallbackStore registerSamplesToAverageCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback on the samples-to-average value of this encoder.
+ *
+ * @param callback the callback that will be called whenever the samples-to-average is changed
+ * @param initialNotify if true, the callback will be run on the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerSamplesToAverageCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = EncoderDataJNI.registerSamplesToAverageCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, EncoderDataJNI::cancelSamplesToAverageCallback);
}
+
+ /**
+ * Get the samples-to-average value.
+ *
+ * @return the samples-to-average value
+ */
public int getSamplesToAverage() {
return EncoderDataJNI.getSamplesToAverage(m_index);
}
+
+ /**
+ * Set the samples-to-average value.
+ *
+ * @param samplesToAverage the new value
+ */
public void setSamplesToAverage(int samplesToAverage) {
EncoderDataJNI.setSamplesToAverage(m_index, samplesToAverage);
}
+ /**
+ * Change the encoder distance.
+ *
+ * @param distance the new distance
+ */
public void setDistance(double distance) {
EncoderDataJNI.setDistance(m_index, distance);
}
+ /**
+ * Read the distance of the encoder.
+ *
+ * @return the encoder distance
+ */
public double getDistance() {
return EncoderDataJNI.getDistance(m_index);
}
+ /**
+ * Change the rate of the encoder.
+ *
+ * @param rate the new rate
+ */
public void setRate(double rate) {
EncoderDataJNI.setRate(m_index, rate);
}
+ /**
+ * Get the rate of the encoder.
+ *
+ * @return the rate of change
+ */
public double getRate() {
return EncoderDataJNI.getRate(m_index);
}
+ /** Resets all simulation data for this encoder. */
public void resetData() {
EncoderDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/Field2d.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/Field2d.java
deleted file mode 100644
index bbda95a..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/Field2d.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.simulation;
-
-import edu.wpi.first.hal.SimDevice;
-import edu.wpi.first.hal.SimDouble;
-import edu.wpi.first.wpilibj.geometry.Pose2d;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
-import edu.wpi.first.wpilibj.geometry.Translation2d;
-
-/**
- * 2D representation of game field (for simulation).
- *
- * <p>In non-simulation mode this simply stores and returns the robot pose.
- *
- * <p>The robot pose is the actual location shown on the simulation view.
- * This may or may not match the robot's internal odometry. For example, if
- * the robot is shown at a particular starting location, the pose in this
- * class would represent the actual location on the field, but the robot's
- * internal state might have a 0,0,0 pose (unless it's initialized to
- * something different).
- *
- * <p>As the user is able to edit the pose, code performing updates should get
- * the robot pose, transform it as appropriate (e.g. based on simulated wheel
- * velocity), and set the new pose.
- */
-public class Field2d {
- public Field2d() {
- m_device = SimDevice.create("Field2D");
- if (m_device != null) {
- m_x = m_device.createDouble("x", false, 0.0);
- m_y = m_device.createDouble("y", false, 0.0);
- m_rot = m_device.createDouble("rot", false, 0.0);
- }
- }
-
- /**
- * Set the robot pose from a Pose object.
- *
- * @param pose 2D pose
- */
- public void setRobotPose(Pose2d pose) {
- if (m_device != null) {
- Translation2d translation = pose.getTranslation();
- m_x.set(translation.getX());
- m_y.set(translation.getY());
- m_rot.set(pose.getRotation().getDegrees());
- } else {
- m_pose = pose;
- }
- }
-
- /**
- * Set the robot pose from x, y, and rotation.
- *
- * @param xMeters X location, in meters
- * @param yMeters Y location, in meters
- * @param rotation rotation
- */
- public void setRobotPose(double xMeters, double yMeters, Rotation2d rotation) {
- if (m_device != null) {
- m_x.set(xMeters);
- m_y.set(yMeters);
- m_rot.set(rotation.getDegrees());
- } else {
- m_pose = new Pose2d(xMeters, yMeters, rotation);
- }
- }
-
- /**
- * Get the robot pose.
- *
- * @return 2D pose
- */
- public Pose2d getRobotPose() {
- if (m_device != null) {
- return new Pose2d(m_x.get(), m_y.get(), Rotation2d.fromDegrees(m_rot.get()));
- } else {
- return m_pose;
- }
- }
-
- private Pose2d m_pose;
-
- @SuppressWarnings("MemberName")
- private final SimDevice m_device;
-
- @SuppressWarnings("MemberName")
- private SimDouble m_x;
-
- @SuppressWarnings("MemberName")
- private SimDouble m_y;
-
- private SimDouble m_rot;
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/FlywheelSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/FlywheelSim.java
index 785facc..aaf13de 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/FlywheelSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/FlywheelSim.java
@@ -1,22 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import edu.wpi.first.wpilibj.system.LinearSystem;
-import edu.wpi.first.wpilibj.system.plant.DCMotor;
-import edu.wpi.first.wpilibj.system.plant.LinearSystemId;
-import edu.wpi.first.wpilibj.util.Units;
-import edu.wpi.first.wpiutil.math.Matrix;
-import edu.wpi.first.wpiutil.math.numbers.N1;
+import edu.wpi.first.math.Matrix;
+import edu.wpi.first.math.numbers.N1;
+import edu.wpi.first.math.system.LinearSystem;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.math.system.plant.LinearSystemId;
+import edu.wpi.first.math.util.Units;
-/**
- * Represents a simulated flywheel mechanism.
- */
+/** Represents a simulated flywheel mechanism. */
public class FlywheelSim extends LinearSystemSim<N1, N1, N1> {
// Gearbox for the flywheel.
private final DCMotor m_gearbox;
@@ -27,10 +22,9 @@
/**
* Creates a simulated flywheel mechanism.
*
- * @param plant The linear system that represents the flywheel.
+ * @param plant The linear system that represents the flywheel.
* @param gearbox The type of and number of motors in the flywheel gearbox.
- * @param gearing The gearing of the flywheel (numbers greater than 1
- * represent reductions).
+ * @param gearing The gearing of the flywheel (numbers greater than 1 represent reductions).
*/
public FlywheelSim(LinearSystem<N1, N1, N1> plant, DCMotor gearbox, double gearing) {
super(plant);
@@ -41,15 +35,16 @@
/**
* Creates a simulated flywheel mechanism.
*
- * @param plant The linear system that represents the flywheel.
- * @param gearbox The type of and number of motors in the flywheel
- * gearbox.
- * @param gearing The gearing of the flywheel (numbers greater
- * than 1 represent reductions).
+ * @param plant The linear system that represents the flywheel.
+ * @param gearbox The type of and number of motors in the flywheel gearbox.
+ * @param gearing The gearing of the flywheel (numbers greater than 1 represent reductions).
* @param measurementStdDevs The standard deviations of the measurements.
*/
- public FlywheelSim(LinearSystem<N1, N1, N1> plant, DCMotor gearbox, double gearing,
- Matrix<N1, N1> measurementStdDevs) {
+ public FlywheelSim(
+ LinearSystem<N1, N1, N1> plant,
+ DCMotor gearbox,
+ double gearing,
+ Matrix<N1, N1> measurementStdDevs) {
super(plant, measurementStdDevs);
m_gearbox = gearbox;
m_gearing = gearing;
@@ -58,15 +53,14 @@
/**
* Creates a simulated flywheel mechanism.
*
- * @param gearbox The type of and number of motors in the flywheel gearbox.
- * @param gearing The gearing of the flywheel (numbers greater than 1
- * represent reductions).
- * @param jKgMetersSquared The moment of inertia of the flywheel. If this is unknown,
- * use the {@link #FlywheelSim(LinearSystem, DCMotor, double, Matrix)}
- * constructor.
+ * @param gearbox The type of and number of motors in the flywheel gearbox.
+ * @param gearing The gearing of the flywheel (numbers greater than 1 represent reductions).
+ * @param jKgMetersSquared The moment of inertia of the flywheel. If this is unknown, use the
+ * {@link #FlywheelSim(LinearSystem, DCMotor, double, Matrix)} constructor.
*/
+ @SuppressWarnings("ParameterName")
public FlywheelSim(DCMotor gearbox, double gearing, double jKgMetersSquared) {
- super(LinearSystemId.createFlywheelSystem(gearbox, gearing, jKgMetersSquared));
+ super(LinearSystemId.createFlywheelSystem(gearbox, jKgMetersSquared, gearing));
m_gearbox = gearbox;
m_gearing = gearing;
}
@@ -74,18 +68,17 @@
/**
* Creates a simulated flywheel mechanism.
*
- * @param gearbox The type of and number of motors in the flywheel
- * gearbox.
- * @param gearing The gearing of the flywheel (numbers greater
- * than 1 represent reductions).
- * @param jKgMetersSquared The moment of inertia of the flywheel. If this is unknown,
- * use the {@link #FlywheelSim(LinearSystem, DCMotor, double, Matrix)}
- * constructor.
+ * @param gearbox The type of and number of motors in the flywheel gearbox.
+ * @param gearing The gearing of the flywheel (numbers greater than 1 represent reductions).
+ * @param jKgMetersSquared The moment of inertia of the flywheel. If this is unknown, use the
+ * {@link #FlywheelSim(LinearSystem, DCMotor, double, Matrix)} constructor.
* @param measurementStdDevs The standard deviations of the measurements.
*/
- public FlywheelSim(DCMotor gearbox, double gearing, double jKgMetersSquared,
- Matrix<N1, N1> measurementStdDevs) {
- super(LinearSystemId.createFlywheelSystem(gearbox, gearing, jKgMetersSquared),
+ @SuppressWarnings("ParameterName")
+ public FlywheelSim(
+ DCMotor gearbox, double gearing, double jKgMetersSquared, Matrix<N1, N1> measurementStdDevs) {
+ super(
+ LinearSystemId.createFlywheelSystem(gearbox, jKgMetersSquared, gearing),
measurementStdDevs);
m_gearbox = gearbox;
m_gearing = gearing;
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/GenericHIDSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/GenericHIDSim.java
index 506be52..c5878ca 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/GenericHIDSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/GenericHIDSim.java
@@ -1,17 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.wpilibj.GenericHID;
-/**
- * Class to control a simulated generic joystick.
- */
+/** Class to control a simulated generic joystick. */
public class GenericHIDSim {
protected final int m_port;
@@ -33,65 +28,135 @@
m_port = port;
}
- /**
- * Updates joystick data so that new values are visible to the user program.
- */
+ /** Updates joystick data so that new values are visible to the user program. */
public void notifyNewData() {
DriverStationSim.notifyNewData();
}
+ /**
+ * Set the value of a given button.
+ *
+ * @param button the button to set
+ * @param value the new value
+ */
public void setRawButton(int button, boolean value) {
DriverStationSim.setJoystickButton(m_port, button, value);
}
+ /**
+ * Set the value of a given axis.
+ *
+ * @param axis the axis to set
+ * @param value the new value
+ */
public void setRawAxis(int axis, double value) {
DriverStationSim.setJoystickAxis(m_port, axis, value);
}
+ /**
+ * Set the value of a given POV.
+ *
+ * @param pov the POV to set
+ * @param value the new value
+ */
public void setPOV(int pov, int value) {
DriverStationSim.setJoystickPOV(m_port, pov, value);
}
+ /**
+ * Set the value of the default POV (port 0).
+ *
+ * @param value the new value
+ */
public void setPOV(int value) {
setPOV(0, value);
}
+ /**
+ * Set the axis count of this device.
+ *
+ * @param count the new axis count
+ */
public void setAxisCount(int count) {
DriverStationSim.setJoystickAxisCount(m_port, count);
}
+ /**
+ * Set the POV count of this device.
+ *
+ * @param count the new POV count
+ */
public void setPOVCount(int count) {
DriverStationSim.setJoystickPOVCount(m_port, count);
}
+ /**
+ * Set the button count of this device.
+ *
+ * @param count the new button count
+ */
public void setButtonCount(int count) {
DriverStationSim.setJoystickButtonCount(m_port, count);
}
+ /**
+ * Set the type of this device.
+ *
+ * @param type the new device type
+ */
public void setType(GenericHID.HIDType type) {
DriverStationSim.setJoystickType(m_port, type.value);
}
+ /**
+ * Set the name of this device.
+ *
+ * @param name the new device name
+ */
public void setName(String name) {
DriverStationSim.setJoystickName(m_port, name);
}
+ /**
+ * Set the type of an axis.
+ *
+ * @param axis the axis
+ * @param type the type
+ */
public void setAxisType(int axis, int type) {
DriverStationSim.setJoystickAxisType(m_port, axis, type);
}
+ /**
+ * Read the output of a button.
+ *
+ * @param outputNumber the button number
+ * @return the value of the button (true = pressed)
+ */
public boolean getOutput(int outputNumber) {
long outputs = getOutputs();
return (outputs & (1 << (outputNumber - 1))) != 0;
}
+ /**
+ * Get the encoded 16-bit integer that passes button values.
+ *
+ * @return the button values
+ */
public long getOutputs() {
return DriverStationSim.getJoystickOutputs(m_port);
}
+ /**
+ * Get the joystick rumble.
+ *
+ * @param type the rumble to read
+ * @return the rumble value
+ */
public double getRumble(GenericHID.RumbleType type) {
- int value = DriverStationSim.getJoystickRumble(
- m_port, type == GenericHID.RumbleType.kLeftRumble ? 0 : 1);
+ int value =
+ DriverStationSim.getJoystickRumble(
+ m_port, type == GenericHID.RumbleType.kLeftRumble ? 0 : 1);
return value / 65535.0;
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/I2CSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/I2CSim.java
index 1252eeb..986e310 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/I2CSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/I2CSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -12,34 +9,75 @@
import edu.wpi.first.hal.simulation.I2CDataJNI;
import edu.wpi.first.hal.simulation.NotifyCallback;
+/** A class to control a simulated I2C device. */
public class I2CSim {
private final int m_index;
+ /**
+ * Construct a new I2C simulation object.
+ *
+ * @param index the HAL index of the I2C object
+ */
public I2CSim(int index) {
m_index = index;
}
+ /**
+ * Register a callback to be run when this I2C device is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = I2CDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, I2CDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check whether this I2C device has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return I2CDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Define whether this I2C device has been initialized.
+ *
+ * @param initialized whether this device is initialized
+ */
public void setInitialized(boolean initialized) {
I2CDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback to be run whenever a `read` operation is done.
+ *
+ * @param callback the callback that is run on `read` operations
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerReadCallback(BufferCallback callback) {
int uid = I2CDataJNI.registerReadCallback(m_index, callback);
return new CallbackStore(m_index, uid, I2CDataJNI::cancelReadCallback);
}
+ /**
+ * Register a callback to be run whenever a `write` operation is done.
+ *
+ * @param callback the callback that is run on `write` operations
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerWriteCallback(ConstBufferCallback callback) {
int uid = I2CDataJNI.registerWriteCallback(m_index, callback);
return new CallbackStore(m_index, uid, I2CDataJNI::cancelWriteCallback);
}
+ /** Reset all I2C simulation data. */
public void resetData() {
I2CDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/JoystickSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/JoystickSim.java
index d1d7100..f55b038 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/JoystickSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/JoystickSim.java
@@ -1,17 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.wpilibj.Joystick;
-/**
- * Class to control a simulated joystick.
- */
+/** Class to control a simulated joystick. */
public class JoystickSim extends GenericHIDSim {
private Joystick m_joystick;
@@ -42,34 +37,68 @@
setPOVCount(1);
}
+ /**
+ * Set the X value of the joystick.
+ *
+ * @param value the new X value
+ */
public void setX(double value) {
setRawAxis(m_joystick != null ? m_joystick.getXChannel() : Joystick.kDefaultXChannel, value);
}
+ /**
+ * Set the Y value of the joystick.
+ *
+ * @param value the new Y value
+ */
public void setY(double value) {
setRawAxis(m_joystick != null ? m_joystick.getYChannel() : Joystick.kDefaultYChannel, value);
}
+ /**
+ * Set the Z value of the joystick.
+ *
+ * @param value the new Z value
+ */
public void setZ(double value) {
setRawAxis(m_joystick != null ? m_joystick.getZChannel() : Joystick.kDefaultZChannel, value);
}
+ /**
+ * Set the twist value of the joystick.
+ *
+ * @param value the new twist value
+ */
public void setTwist(double value) {
setRawAxis(
- m_joystick != null ? m_joystick.getTwistChannel() : Joystick.kDefaultTwistChannel,
- value);
+ m_joystick != null ? m_joystick.getTwistChannel() : Joystick.kDefaultTwistChannel, value);
}
+ /**
+ * Set the throttle value of the joystick.
+ *
+ * @param value the new throttle value
+ */
public void setThrottle(double value) {
setRawAxis(
m_joystick != null ? m_joystick.getThrottleChannel() : Joystick.kDefaultThrottleChannel,
value);
}
+ /**
+ * Set the trigger value of the joystick.
+ *
+ * @param state the new value
+ */
public void setTrigger(boolean state) {
setRawButton(1, state);
}
+ /**
+ * Set the top state of the joystick.
+ *
+ * @param state the new state
+ */
public void setTop(boolean state) {
setRawButton(2, state);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/LinearSystemSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/LinearSystemSim.java
index dc69ffa..2b4e9a9 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/LinearSystemSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/LinearSystemSim.java
@@ -1,24 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
+import edu.wpi.first.math.Matrix;
+import edu.wpi.first.math.Num;
+import edu.wpi.first.math.StateSpaceUtil;
+import edu.wpi.first.math.numbers.N1;
+import edu.wpi.first.math.system.LinearSystem;
+import edu.wpi.first.wpilibj.RobotController;
import org.ejml.MatrixDimensionException;
import org.ejml.simple.SimpleMatrix;
-import edu.wpi.first.wpilibj.math.StateSpaceUtil;
-import edu.wpi.first.wpilibj.system.LinearSystem;
-import edu.wpi.first.wpiutil.math.Matrix;
-import edu.wpi.first.wpiutil.math.Num;
-import edu.wpi.first.wpiutil.math.numbers.N1;
-
/**
- * This class helps simulate linear systems. To use this class, do the following in the
- * {@link edu.wpi.first.wpilibj.IterativeRobotBase#simulationPeriodic} method.
+ * This class helps simulate linear systems. To use this class, do the following in the {@link
+ * edu.wpi.first.wpilibj.IterativeRobotBase#simulationPeriodic} method.
*
* <p>Call {@link #setInput(double...)} with the inputs to the system (usually voltage).
*
@@ -26,8 +23,8 @@
*
* <p>Set simulated sensor readings with the simulated positions in {@link #getOutput()}
*
- * @param <States> The number of states of the system.
- * @param <Inputs> The number of inputs to the system.
+ * @param <States> The number of states of the system.
+ * @param <Inputs> The number of inputs to the system.
* @param <Outputs> The number of outputs of the system.
*/
@SuppressWarnings("ClassTypeParameterName")
@@ -38,8 +35,10 @@
// Variables for state, output, and input.
@SuppressWarnings("MemberName")
protected Matrix<States, N1> m_x;
+
@SuppressWarnings("MemberName")
protected Matrix<Outputs, N1> m_y;
+
@SuppressWarnings("MemberName")
protected Matrix<Inputs, N1> m_u;
@@ -59,11 +58,12 @@
/**
* Creates a simulated generic linear system with measurement noise.
*
- * @param system The system being controlled.
- * @param measurementStdDevs Standard deviations of measurements.
+ * @param system The system being controlled.
+ * @param measurementStdDevs Standard deviations of measurements. Can be null if no noise is
+ * desired.
*/
- public LinearSystemSim(LinearSystem<States, Inputs, Outputs> system,
- Matrix<Outputs, N1> measurementStdDevs) {
+ public LinearSystemSim(
+ LinearSystem<States, Inputs, Outputs> system, Matrix<Outputs, N1> measurementStdDevs) {
this.m_plant = system;
this.m_measurementStdDevs = measurementStdDevs;
@@ -115,18 +115,20 @@
*
* @param u The system inputs.
*/
+ @SuppressWarnings("ParameterName")
public void setInput(Matrix<Inputs, N1> u) {
- this.m_u = u;
+ this.m_u = clampInput(u);
}
/**
* Sets the system inputs.
*
- * @param row The row in the input matrix to set.
+ * @param row The row in the input matrix to set.
* @param value The value to set the row to.
*/
public void setInput(int row, double value) {
m_u.set(row, 0, value);
+ m_u = clampInput(m_u);
}
/**
@@ -134,10 +136,11 @@
*
* @param u An array of doubles that represent the inputs of the system.
*/
+ @SuppressWarnings("ParameterName")
public void setInput(double... u) {
if (u.length != m_u.getNumRows()) {
- throw new MatrixDimensionException("Malformed input! Got " + u.length
- + " elements instead of " + m_u.getNumRows());
+ throw new MatrixDimensionException(
+ "Malformed input! Got " + u.length + " elements instead of " + m_u.getNumRows());
}
m_u = new Matrix<>(new SimpleMatrix(m_u.getNumRows(), 1, true, u));
}
@@ -165,12 +168,24 @@
* Updates the state estimate of the system.
*
* @param currentXhat The current state estimate.
- * @param u The system inputs (usually voltage).
- * @param dtSeconds The time difference between controller updates.
+ * @param u The system inputs (usually voltage).
+ * @param dtSeconds The time difference between controller updates.
* @return The new state.
*/
- protected Matrix<States, N1> updateX(Matrix<States, N1> currentXhat,
- Matrix<Inputs, N1> u, double dtSeconds) {
+ @SuppressWarnings("ParameterName")
+ protected Matrix<States, N1> updateX(
+ Matrix<States, N1> currentXhat, Matrix<Inputs, N1> u, double dtSeconds) {
return m_plant.calculateX(currentXhat, u, dtSeconds);
}
+
+ /**
+ * Clamp the input vector such that no element exceeds the given voltage. If any does, the
+ * relative magnitudes of the input will be maintained.
+ *
+ * @param u The input vector.
+ * @return The normalized input.
+ */
+ protected Matrix<Inputs, N1> clampInput(Matrix<Inputs, N1> u) {
+ return StateSpaceUtil.normalizeInputVector(u, RobotController.getBatteryVoltage());
+ }
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/Mechanism2D.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/Mechanism2D.java
deleted file mode 100644
index 7006c91..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/Mechanism2D.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.simulation;
-
-import edu.wpi.first.hal.SimDevice;
-import edu.wpi.first.hal.SimDouble;
-import java.util.HashMap;
-import java.util.Map;
-
-public class Mechanism2D {
- private static final SimDevice m_device = SimDevice.create("Mechanism2D");
- private static final Map<String, SimDouble> m_createdItems = new HashMap<String, SimDouble>();
-
- /**
- * Set/Create the angle of a ligament.
- *
- * @param ligamentPath json path to the ligament
- * @param angle to set the ligament
- */
- public void setLigamentAngle(String ligamentPath, float angle) {
- ligamentPath = ligamentPath + "/angle";
- if (m_device != null) {
- if (!m_createdItems.containsKey(ligamentPath)) {
- m_createdItems.put(ligamentPath, m_device.createDouble(ligamentPath, false, angle));
- }
- m_createdItems.get(ligamentPath).set(angle);
- }
- }
-
- /**
- * Set/Create the length of a ligament.
- *
- * @param ligamentPath json path to the ligament
- * @param length to set the ligament
- */
- public void setLigamentLength(String ligamentPath, float length) {
- ligamentPath = ligamentPath + "/length";
- if (m_device != null) {
- if (!m_createdItems.containsKey(ligamentPath)) {
- m_createdItems.put(ligamentPath, m_device.createDouble(ligamentPath, false, length));
- }
- m_createdItems.get(ligamentPath).set(length);
- }
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/NotifierSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/NotifierSim.java
index 3778e36..a5be97f 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/NotifierSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/NotifierSim.java
@@ -1,20 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.simulation.NotifierDataJNI;
-/**
- * Class to control simulated notifiers.
- */
+/** Class to control simulated notifiers. */
public final class NotifierSim {
- private NotifierSim() {
- }
+ private NotifierSim() {}
/**
* Gets the timeout of the next notifier.
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PCMSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PCMSim.java
deleted file mode 100644
index 7881f0c..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PCMSim.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.simulation;
-
-import edu.wpi.first.hal.simulation.NotifyCallback;
-import edu.wpi.first.hal.simulation.PCMDataJNI;
-import edu.wpi.first.wpilibj.Compressor;
-import edu.wpi.first.wpilibj.SensorUtil;
-
-/**
- * Class to control a simulated Pneumatic Control Module (PCM).
- */
-public class PCMSim {
- private final int m_index;
-
- /**
- * Constructs for the default PCM.
- */
- public PCMSim() {
- m_index = SensorUtil.getDefaultSolenoidModule();
- }
-
- /**
- * Constructs from a PCM module number (CAN ID).
- *
- * @param module module number
- */
- public PCMSim(int module) {
- m_index = module;
- }
-
- /**
- * Constructs from a Compressor object.
- *
- * @param compressor Compressor connected to PCM to simulate
- */
- public PCMSim(Compressor compressor) {
- m_index = compressor.getModule();
- }
-
- public CallbackStore registerSolenoidInitializedCallback(int channel, NotifyCallback callback, boolean initialNotify) {
- int uid = PCMDataJNI.registerSolenoidInitializedCallback(m_index, channel, callback, initialNotify);
- return new CallbackStore(m_index, channel, uid, PCMDataJNI::cancelSolenoidInitializedCallback);
- }
- public boolean getSolenoidInitialized(int channel) {
- return PCMDataJNI.getSolenoidInitialized(m_index, channel);
- }
- public void setSolenoidInitialized(int channel, boolean solenoidInitialized) {
- PCMDataJNI.setSolenoidInitialized(m_index, channel, solenoidInitialized);
- }
-
- public CallbackStore registerSolenoidOutputCallback(int channel, NotifyCallback callback, boolean initialNotify) {
- int uid = PCMDataJNI.registerSolenoidOutputCallback(m_index, channel, callback, initialNotify);
- return new CallbackStore(m_index, channel, uid, PCMDataJNI::cancelSolenoidOutputCallback);
- }
- public boolean getSolenoidOutput(int channel) {
- return PCMDataJNI.getSolenoidOutput(m_index, channel);
- }
- public void setSolenoidOutput(int channel, boolean solenoidOutput) {
- PCMDataJNI.setSolenoidOutput(m_index, channel, solenoidOutput);
- }
-
- public CallbackStore registerCompressorInitializedCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = PCMDataJNI.registerCompressorInitializedCallback(m_index, callback, initialNotify);
- return new CallbackStore(m_index, uid, PCMDataJNI::cancelCompressorInitializedCallback);
- }
- public boolean getCompressorInitialized() {
- return PCMDataJNI.getCompressorInitialized(m_index);
- }
- public void setCompressorInitialized(boolean compressorInitialized) {
- PCMDataJNI.setCompressorInitialized(m_index, compressorInitialized);
- }
-
- public CallbackStore registerCompressorOnCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = PCMDataJNI.registerCompressorOnCallback(m_index, callback, initialNotify);
- return new CallbackStore(m_index, uid, PCMDataJNI::cancelCompressorOnCallback);
- }
- public boolean getCompressorOn() {
- return PCMDataJNI.getCompressorOn(m_index);
- }
- public void setCompressorOn(boolean compressorOn) {
- PCMDataJNI.setCompressorOn(m_index, compressorOn);
- }
-
- public CallbackStore registerClosedLoopEnabledCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = PCMDataJNI.registerClosedLoopEnabledCallback(m_index, callback, initialNotify);
- return new CallbackStore(m_index, uid, PCMDataJNI::cancelClosedLoopEnabledCallback);
- }
- public boolean getClosedLoopEnabled() {
- return PCMDataJNI.getClosedLoopEnabled(m_index);
- }
- public void setClosedLoopEnabled(boolean closedLoopEnabled) {
- PCMDataJNI.setClosedLoopEnabled(m_index, closedLoopEnabled);
- }
-
- public CallbackStore registerPressureSwitchCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = PCMDataJNI.registerPressureSwitchCallback(m_index, callback, initialNotify);
- return new CallbackStore(m_index, uid, PCMDataJNI::cancelPressureSwitchCallback);
- }
- public boolean getPressureSwitch() {
- return PCMDataJNI.getPressureSwitch(m_index);
- }
- public void setPressureSwitch(boolean pressureSwitch) {
- PCMDataJNI.setPressureSwitch(m_index, pressureSwitch);
- }
-
- public CallbackStore registerCompressorCurrentCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = PCMDataJNI.registerCompressorCurrentCallback(m_index, callback, initialNotify);
- return new CallbackStore(m_index, uid, PCMDataJNI::cancelCompressorCurrentCallback);
- }
- public double getCompressorCurrent() {
- return PCMDataJNI.getCompressorCurrent(m_index);
- }
- public void setCompressorCurrent(double compressorCurrent) {
- PCMDataJNI.setCompressorCurrent(m_index, compressorCurrent);
- }
-
- public void resetData() {
- PCMDataJNI.resetData(m_index);
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PDPSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PDPSim.java
index ad57973..eef8ccf 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PDPSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PDPSim.java
@@ -1,25 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.simulation.NotifyCallback;
-import edu.wpi.first.hal.simulation.PDPDataJNI;
-import edu.wpi.first.wpilibj.PowerDistributionPanel;
+import edu.wpi.first.hal.simulation.PowerDistributionDataJNI;
+import edu.wpi.first.wpilibj.PowerDistribution;
-/**
- * Class to control a simulated Power Distribution Panel (PDP).
- */
+/** Class to control a simulated Power Distribution Panel (PDP). */
public class PDPSim {
private final int m_index;
- /**
- * Constructs for the default PDP.
- */
+ /** Constructs for the default PDP. */
public PDPSim() {
m_index = 0;
}
@@ -34,59 +27,148 @@
}
/**
- * Constructs from a PowerDistributionPanel object.
+ * Constructs from a PowerDistribution object.
*
- * @param pdp PowerDistributionPanel to simulate
+ * @param pdp PowerDistribution to simulate
*/
- public PDPSim(PowerDistributionPanel pdp) {
+ public PDPSim(PowerDistribution pdp) {
m_index = pdp.getModule();
}
+ /**
+ * Register a callback to be run when the PDP is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = PDPDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
- return new CallbackStore(m_index, uid, PDPDataJNI::cancelInitializedCallback);
+ int uid =
+ PowerDistributionDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, PowerDistributionDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check whether the PDP has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
- return PDPDataJNI.getInitialized(m_index);
+ return PowerDistributionDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Define whether the PDP has been initialized.
+ *
+ * @param initialized whether this object is initialized
+ */
public void setInitialized(boolean initialized) {
- PDPDataJNI.setInitialized(m_index, initialized);
+ PowerDistributionDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback to be run whenever the PDP temperature changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerTemperatureCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = PDPDataJNI.registerTemperatureCallback(m_index, callback, initialNotify);
- return new CallbackStore(m_index, uid, PDPDataJNI::cancelTemperatureCallback);
+ int uid =
+ PowerDistributionDataJNI.registerTemperatureCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, PowerDistributionDataJNI::cancelTemperatureCallback);
}
+
+ /**
+ * Check the temperature of the PDP.
+ *
+ * @return the PDP temperature
+ */
public double getTemperature() {
- return PDPDataJNI.getTemperature(m_index);
+ return PowerDistributionDataJNI.getTemperature(m_index);
}
+
+ /**
+ * Define the PDP temperature.
+ *
+ * @param temperature the new PDP temperature
+ */
public void setTemperature(double temperature) {
- PDPDataJNI.setTemperature(m_index, temperature);
+ PowerDistributionDataJNI.setTemperature(m_index, temperature);
}
+ /**
+ * Register a callback to be run whenever the PDP voltage changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerVoltageCallback(NotifyCallback callback, boolean initialNotify) {
- int uid = PDPDataJNI.registerVoltageCallback(m_index, callback, initialNotify);
- return new CallbackStore(m_index, uid, PDPDataJNI::cancelVoltageCallback);
+ int uid = PowerDistributionDataJNI.registerVoltageCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, PowerDistributionDataJNI::cancelVoltageCallback);
}
+
+ /**
+ * Check the PDP voltage.
+ *
+ * @return the PDP voltage.
+ */
public double getVoltage() {
- return PDPDataJNI.getVoltage(m_index);
+ return PowerDistributionDataJNI.getVoltage(m_index);
}
+
+ /**
+ * Set the PDP voltage.
+ *
+ * @param voltage the new PDP voltage
+ */
public void setVoltage(double voltage) {
- PDPDataJNI.setVoltage(m_index, voltage);
+ PowerDistributionDataJNI.setVoltage(m_index, voltage);
}
- public CallbackStore registerCurrentCallback(int channel, NotifyCallback callback, boolean initialNotify) {
- int uid = PDPDataJNI.registerCurrentCallback(m_index, channel, callback, initialNotify);
- return new CallbackStore(m_index, channel, uid, PDPDataJNI::cancelCurrentCallback);
+ /**
+ * Register a callback to be run whenever the current of a specific channel changes.
+ *
+ * @param channel the channel
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerCurrentCallback(
+ int channel, NotifyCallback callback, boolean initialNotify) {
+ int uid =
+ PowerDistributionDataJNI.registerCurrentCallback(m_index, channel, callback, initialNotify);
+ return new CallbackStore(
+ m_index, channel, uid, PowerDistributionDataJNI::cancelCurrentCallback);
}
+
+ /**
+ * Read the current in one of the PDP channels.
+ *
+ * @param channel the channel to check
+ * @return the current in the given channel
+ */
public double getCurrent(int channel) {
- return PDPDataJNI.getCurrent(m_index, channel);
- }
- public void setCurrent(int channel, double current) {
- PDPDataJNI.setCurrent(m_index, channel, current);
+ return PowerDistributionDataJNI.getCurrent(m_index, channel);
}
+ /**
+ * Change the current in the given channel.
+ *
+ * @param channel the channel to edit
+ * @param current the new current for the channel
+ */
+ public void setCurrent(int channel, double current) {
+ PowerDistributionDataJNI.setCurrent(m_index, channel, current);
+ }
+
+ /** Reset all PDP simulation data. */
public void resetData() {
- PDPDataJNI.resetData(m_index);
+ PowerDistributionDataJNI.resetData(m_index);
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PS4ControllerSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PS4ControllerSim.java
new file mode 100644
index 0000000..69109b8
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PS4ControllerSim.java
@@ -0,0 +1,212 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import edu.wpi.first.wpilibj.PS4Controller;
+
+/** Class to control a simulated PS4 controller. */
+public class PS4ControllerSim extends GenericHIDSim {
+ /**
+ * Constructs from a PS4Controller object.
+ *
+ * @param joystick controller to simulate
+ */
+ public PS4ControllerSim(PS4Controller joystick) {
+ super(joystick);
+ setAxisCount(6);
+ setButtonCount(14);
+ }
+
+ /**
+ * Constructs from a joystick port number.
+ *
+ * @param port port number
+ */
+ public PS4ControllerSim(int port) {
+ super(port);
+ setAxisCount(6);
+ setButtonCount(14);
+ }
+
+ /**
+ * Change the X axis value of the controller's left stick.
+ *
+ * @param value the new value
+ */
+ public void setLeftX(double value) {
+ setRawAxis(PS4Controller.Axis.kLeftX.value, value);
+ }
+
+ /**
+ * Change the X axis value of the controller's right stick.
+ *
+ * @param value the new value
+ */
+ public void setRightX(double value) {
+ setRawAxis(PS4Controller.Axis.kRightX.value, value);
+ }
+
+ /**
+ * Change the Y axis value of the controller's left stick.
+ *
+ * @param value the new value
+ */
+ public void setLeftY(double value) {
+ setRawAxis(PS4Controller.Axis.kLeftY.value, value);
+ }
+
+ /**
+ * Change the Y axis value of the controller's right stick.
+ *
+ * @param value the new value
+ */
+ public void setRightY(double value) {
+ setRawAxis(PS4Controller.Axis.kRightY.value, value);
+ }
+
+ /**
+ * Change the L2 axis axis value of the controller.
+ *
+ * @param value the new value
+ */
+ public void setL2Axis(double value) {
+ setRawAxis(PS4Controller.Axis.kL2.value, value);
+ }
+
+ /**
+ * Change the R2 axis value of the controller.
+ *
+ * @param value the new value
+ */
+ public void setR2Axis(double value) {
+ setRawAxis(PS4Controller.Axis.kR2.value, value);
+ }
+
+ /**
+ * Change the value of the Square button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setSquareButton(boolean value) {
+ setRawButton(PS4Controller.Button.kSquare.value, value);
+ }
+
+ /**
+ * Change the value of the Cross button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setCrossButton(boolean value) {
+ setRawButton(PS4Controller.Button.kCross.value, value);
+ }
+
+ /**
+ * Change the value of the Circle button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setCircleButton(boolean value) {
+ setRawButton(PS4Controller.Button.kCircle.value, value);
+ }
+
+ /**
+ * Change the value of the Triangle button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setTriangleButton(boolean value) {
+ setRawButton(PS4Controller.Button.kTriangle.value, value);
+ }
+
+ /**
+ * Change the value of the L1 button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setL1Button(boolean value) {
+ setRawButton(PS4Controller.Button.kL1.value, value);
+ }
+
+ /**
+ * Change the value of the R1 button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setR1Button(boolean value) {
+ setRawButton(PS4Controller.Button.kR1.value, value);
+ }
+
+ /**
+ * Change the value of the L2 button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setL2Button(boolean value) {
+ setRawButton(PS4Controller.Button.kL2.value, value);
+ }
+
+ /**
+ * Change the value of the R2 button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setR2Button(boolean value) {
+ setRawButton(PS4Controller.Button.kR2.value, value);
+ }
+
+ /**
+ * Change the value of the Share button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setShareButton(boolean value) {
+ setRawButton(PS4Controller.Button.kShare.value, value);
+ }
+
+ /**
+ * Change the value of the Options button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setOptionsButton(boolean value) {
+ setRawButton(PS4Controller.Button.kOptions.value, value);
+ }
+
+ /**
+ * Change the value of the L3 (left stick) button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setL3Button(boolean value) {
+ setRawButton(PS4Controller.Button.kL3.value, value);
+ }
+
+ /**
+ * Change the value of the R3 (right stick) button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setR3Button(boolean value) {
+ setRawButton(PS4Controller.Button.kR3.value, value);
+ }
+
+ /**
+ * Change the value of the PS button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setPSButton(boolean value) {
+ setRawButton(PS4Controller.Button.kPS.value, value);
+ }
+
+ /**
+ * Change the value of the touchpad button on the controller.
+ *
+ * @param value the new value
+ */
+ public void setTouchpad(boolean value) {
+ setRawButton(PS4Controller.Button.kTouchpad.value, value);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PWMSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PWMSim.java
index d0cca92..8a60e52 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PWMSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/PWMSim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -11,9 +8,7 @@
import edu.wpi.first.hal.simulation.PWMDataJNI;
import edu.wpi.first.wpilibj.PWM;
-/**
- * Class to control a simulated PWM output.
- */
+/** Class to control a simulated PWM output. */
public class PWMSim {
private final int m_index;
@@ -35,72 +30,193 @@
m_index = channel;
}
+ /**
+ * Register a callback to be run when the PWM is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check whether the PWM has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return PWMDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Define whether the PWM has been initialized.
+ *
+ * @param initialized whether this object is initialized
+ */
public void setInitialized(boolean initialized) {
PWMDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback to be run when the PWM raw value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerRawValueCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerRawValueCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelRawValueCallback);
}
+
+ /**
+ * Get the PWM raw value.
+ *
+ * @return the PWM raw value
+ */
public int getRawValue() {
return PWMDataJNI.getRawValue(m_index);
}
+
+ /**
+ * Set the PWM raw value.
+ *
+ * @param rawValue the PWM raw value
+ */
public void setRawValue(int rawValue) {
PWMDataJNI.setRawValue(m_index, rawValue);
}
+ /**
+ * Register a callback to be run when the PWM speed changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerSpeedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerSpeedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelSpeedCallback);
}
+
+ /**
+ * Get the PWM speed.
+ *
+ * @return the PWM speed (-1.0 to 1.0)
+ */
public double getSpeed() {
return PWMDataJNI.getSpeed(m_index);
}
+
+ /**
+ * Set the PWM speed.
+ *
+ * @param speed the PWM speed (-1.0 to 1.0)
+ */
public void setSpeed(double speed) {
PWMDataJNI.setSpeed(m_index, speed);
}
+ /**
+ * Register a callback to be run when the PWM position changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerPositionCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerPositionCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelPositionCallback);
}
+
+ /**
+ * Get the PWM position.
+ *
+ * @return the PWM position (0.0 to 1.0)
+ */
public double getPosition() {
return PWMDataJNI.getPosition(m_index);
}
+
+ /**
+ * Set the PWM position.
+ *
+ * @param position the PWM position (0.0 to 1.0)
+ */
public void setPosition(double position) {
PWMDataJNI.setPosition(m_index, position);
}
+ /**
+ * Register a callback to be run when the PWM period scale changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerPeriodScaleCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerPeriodScaleCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelPeriodScaleCallback);
}
+
+ /**
+ * Get the PWM period scale.
+ *
+ * @return the PWM period scale
+ */
public int getPeriodScale() {
return PWMDataJNI.getPeriodScale(m_index);
}
+
+ /**
+ * Set the PWM period scale.
+ *
+ * @param periodScale the PWM period scale
+ */
public void setPeriodScale(int periodScale) {
PWMDataJNI.setPeriodScale(m_index, periodScale);
}
+ /**
+ * Register a callback to be run when the PWM zero latch state changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerZeroLatchCallback(NotifyCallback callback, boolean initialNotify) {
int uid = PWMDataJNI.registerZeroLatchCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, PWMDataJNI::cancelZeroLatchCallback);
}
+
+ /**
+ * Check whether the PWM is zero latched.
+ *
+ * @return true if zero latched
+ */
public boolean getZeroLatch() {
return PWMDataJNI.getZeroLatch(m_index);
}
+
+ /**
+ * Define whether the PWM has been zero latched.
+ *
+ * @param zeroLatch true to indicate zero latched
+ */
public void setZeroLatch(boolean zeroLatch) {
PWMDataJNI.setZeroLatch(m_index, zeroLatch);
}
+ /** Reset all simulation data. */
public void resetData() {
PWMDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/REVPHSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/REVPHSim.java
new file mode 100644
index 0000000..8a5f0f8
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/REVPHSim.java
@@ -0,0 +1,239 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import edu.wpi.first.hal.simulation.NotifyCallback;
+import edu.wpi.first.hal.simulation.REVPHDataJNI;
+import edu.wpi.first.wpilibj.PneumaticsBase;
+import edu.wpi.first.wpilibj.SensorUtil;
+
+/** Class to control a simulated PneumaticHub (PH). */
+@SuppressWarnings("AbbreviationAsWordInName")
+public class REVPHSim {
+ private final int m_index;
+
+ /** Constructs for the default PH. */
+ public REVPHSim() {
+ m_index = SensorUtil.getDefaultREVPHModule();
+ }
+
+ /**
+ * Constructs from a PH module number (CAN ID).
+ *
+ * @param module module number
+ */
+ public REVPHSim(int module) {
+ m_index = module;
+ }
+
+ /**
+ * Constructs from a Compressor object.
+ *
+ * @param module PCM module to simulate
+ */
+ public REVPHSim(PneumaticsBase module) {
+ m_index = module.getModuleNumber();
+ }
+
+ /**
+ * Register a callback to be run when the solenoid output on a channel changes.
+ *
+ * @param channel the channel to monitor
+ * @param callback the callback
+ * @param initialNotify should the callback be run with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerSolenoidOutputCallback(
+ int channel, NotifyCallback callback, boolean initialNotify) {
+ int uid =
+ REVPHDataJNI.registerSolenoidOutputCallback(m_index, channel, callback, initialNotify);
+ return new CallbackStore(m_index, channel, uid, REVPHDataJNI::cancelSolenoidOutputCallback);
+ }
+
+ /**
+ * Check the solenoid output on a specific channel.
+ *
+ * @param channel the channel to check
+ * @return the solenoid output
+ */
+ public boolean getSolenoidOutput(int channel) {
+ return REVPHDataJNI.getSolenoidOutput(m_index, channel);
+ }
+
+ /**
+ * Change the solenoid output on a specific channel.
+ *
+ * @param channel the channel to check
+ * @param solenoidOutput the new solenoid output
+ */
+ public void setSolenoidOutput(int channel, boolean solenoidOutput) {
+ REVPHDataJNI.setSolenoidOutput(m_index, channel, solenoidOutput);
+ }
+
+ /**
+ * Register a callback to be run when the compressor is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
+ int uid = REVPHDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, REVPHDataJNI::cancelInitializedCallback);
+ }
+
+ /**
+ * Check whether the compressor has been initialized.
+ *
+ * @return true if initialized
+ */
+ public boolean getInitialized() {
+ return REVPHDataJNI.getInitialized(m_index);
+ }
+
+ /**
+ * Define whether the compressor has been initialized.
+ *
+ * @param initialized whether the compressor is initialized
+ */
+ public void setInitialized(boolean initialized) {
+ REVPHDataJNI.setInitialized(m_index, initialized);
+ }
+
+ /**
+ * Register a callback to be run when the compressor activates.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerCompressorOnCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = REVPHDataJNI.registerCompressorOnCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, REVPHDataJNI::cancelCompressorOnCallback);
+ }
+
+ /**
+ * Check if the compressor is on.
+ *
+ * @return true if the compressor is active
+ */
+ public boolean getCompressorOn() {
+ return REVPHDataJNI.getCompressorOn(m_index);
+ }
+
+ /**
+ * Set whether the compressor is active.
+ *
+ * @param compressorOn the new value
+ */
+ public void setCompressorOn(boolean compressorOn) {
+ REVPHDataJNI.setCompressorOn(m_index, compressorOn);
+ }
+
+ /**
+ * Register a callback to be run whenever the closed loop state changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerClosedLoopEnabledCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = REVPHDataJNI.registerClosedLoopEnabledCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, REVPHDataJNI::cancelClosedLoopEnabledCallback);
+ }
+
+ /**
+ * Check whether the closed loop compressor control is active.
+ *
+ * @return true if active
+ */
+ public boolean getClosedLoopEnabled() {
+ return REVPHDataJNI.getClosedLoopEnabled(m_index);
+ }
+
+ /**
+ * Turn on/off the closed loop control of the compressor.
+ *
+ * @param closedLoopEnabled whether the control loop is active
+ */
+ public void setClosedLoopEnabled(boolean closedLoopEnabled) {
+ REVPHDataJNI.setClosedLoopEnabled(m_index, closedLoopEnabled);
+ }
+
+ /**
+ * Register a callback to be run whenever the pressure switch value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerPressureSwitchCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = REVPHDataJNI.registerPressureSwitchCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, REVPHDataJNI::cancelPressureSwitchCallback);
+ }
+
+ /**
+ * Check the value of the pressure switch.
+ *
+ * @return the pressure switch value
+ */
+ public boolean getPressureSwitch() {
+ return REVPHDataJNI.getPressureSwitch(m_index);
+ }
+
+ /**
+ * Set the value of the pressure switch.
+ *
+ * @param pressureSwitch the new value
+ */
+ public void setPressureSwitch(boolean pressureSwitch) {
+ REVPHDataJNI.setPressureSwitch(m_index, pressureSwitch);
+ }
+
+ /**
+ * Register a callback to be run whenever the compressor current changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerCompressorCurrentCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = REVPHDataJNI.registerCompressorCurrentCallback(m_index, callback, initialNotify);
+ return new CallbackStore(m_index, uid, REVPHDataJNI::cancelCompressorCurrentCallback);
+ }
+
+ /**
+ * Read the compressor current.
+ *
+ * @return the current of the compressor connected to this module
+ */
+ public double getCompressorCurrent() {
+ return REVPHDataJNI.getCompressorCurrent(m_index);
+ }
+
+ /**
+ * Set the compressor current.
+ *
+ * @param compressorCurrent the new compressor current
+ */
+ public void setCompressorCurrent(double compressorCurrent) {
+ REVPHDataJNI.setCompressorCurrent(m_index, compressorCurrent);
+ }
+
+ /** Reset all simulation data for this object. */
+ public void resetData() {
+ REVPHDataJNI.resetData(m_index);
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RelaySim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RelaySim.java
index dc7441e..b6f2542 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RelaySim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RelaySim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -11,9 +8,7 @@
import edu.wpi.first.hal.simulation.RelayDataJNI;
import edu.wpi.first.wpilibj.Relay;
-/**
- * Class to control a simulated relay.
- */
+/** Class to control a simulated relay. */
public class RelaySim {
private final int m_index;
@@ -35,50 +30,133 @@
m_index = channel;
}
- public CallbackStore registerInitializedForwardCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback to be run when the forward direction is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerInitializedForwardCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RelayDataJNI.registerInitializedForwardCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, RelayDataJNI::cancelInitializedForwardCallback);
}
+
+ /**
+ * Check whether the forward direction has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitializedForward() {
return RelayDataJNI.getInitializedForward(m_index);
}
+
+ /**
+ * Define whether the forward direction has been initialized.
+ *
+ * @param initializedForward whether this object is initialized
+ */
public void setInitializedForward(boolean initializedForward) {
RelayDataJNI.setInitializedForward(m_index, initializedForward);
}
- public CallbackStore registerInitializedReverseCallback(NotifyCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback to be run when the reverse direction is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerInitializedReverseCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RelayDataJNI.registerInitializedReverseCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, RelayDataJNI::cancelInitializedReverseCallback);
}
+
+ /**
+ * Check whether the reverse direction has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitializedReverse() {
return RelayDataJNI.getInitializedReverse(m_index);
}
+
+ /**
+ * Define whether the reverse direction has been initialized.
+ *
+ * @param initializedReverse whether this object is initialized
+ */
public void setInitializedReverse(boolean initializedReverse) {
RelayDataJNI.setInitializedReverse(m_index, initializedReverse);
}
+ /**
+ * Register a callback to be run when the forward direction changes state.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerForwardCallback(NotifyCallback callback, boolean initialNotify) {
int uid = RelayDataJNI.registerForwardCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, RelayDataJNI::cancelForwardCallback);
}
+
+ /**
+ * Check whether the forward direction is active.
+ *
+ * @return true if active
+ */
public boolean getForward() {
return RelayDataJNI.getForward(m_index);
}
+
+ /**
+ * Set whether the forward direction is active.
+ *
+ * @param forward true to make active
+ */
public void setForward(boolean forward) {
RelayDataJNI.setForward(m_index, forward);
}
+ /**
+ * Register a callback to be run when the reverse direction changes state.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerReverseCallback(NotifyCallback callback, boolean initialNotify) {
int uid = RelayDataJNI.registerReverseCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, RelayDataJNI::cancelReverseCallback);
}
+
+ /**
+ * Check whether the reverse direction is active.
+ *
+ * @return true if active
+ */
public boolean getReverse() {
return RelayDataJNI.getReverse(m_index);
}
+
+ /**
+ * Set whether the reverse direction is active.
+ *
+ * @param reverse true to make active
+ */
public void setReverse(boolean reverse) {
RelayDataJNI.setReverse(m_index, reverse);
}
+ /** Reset all simulation data. */
public void resetData() {
RelayDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RoboRioSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RoboRioSim.java
index f90ce0f..976ba4a 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RoboRioSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RoboRioSim.java
@@ -1,200 +1,537 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.hal.simulation.RoboRioDataJNI;
-/**
- * Class to control a simulated RoboRIO.
- */
-@SuppressWarnings({"PMD.ExcessivePublicCount", "PMD.UseUtilityClass"})
-public class RoboRioSim {
- public static CallbackStore registerFPGAButtonCallback(NotifyCallback callback,
- boolean initialNotify) {
+/** A utility class to control a simulated RoboRIO. */
+public final class RoboRioSim {
+ private RoboRioSim() {
+ // Utility class
+ }
+
+ /**
+ * Register a callback to be run when the FPGA button state changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ @SuppressWarnings("AbbreviationAsWordInName")
+ public static CallbackStore registerFPGAButtonCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerFPGAButtonCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelFPGAButtonCallback);
}
+
+ /**
+ * Query the state of the FPGA button.
+ *
+ * @return the FPGA button state
+ */
+ @SuppressWarnings("AbbreviationAsWordInName")
public static boolean getFPGAButton() {
return RoboRioDataJNI.getFPGAButton();
}
- public static void setFPGAButton(boolean fPGAButton) {
- RoboRioDataJNI.setFPGAButton(fPGAButton);
+
+ /**
+ * Define the state of the FPGA button.
+ *
+ * @param fpgaButton the new state
+ */
+ @SuppressWarnings("AbbreviationAsWordInName")
+ public static void setFPGAButton(boolean fpgaButton) {
+ RoboRioDataJNI.setFPGAButton(fpgaButton);
}
- public static CallbackStore registerVInVoltageCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the Vin voltage changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerVInVoltageCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerVInVoltageCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelVInVoltageCallback);
}
+
+ /**
+ * Measure the Vin voltage.
+ *
+ * @return the Vin voltage
+ */
public static double getVInVoltage() {
return RoboRioDataJNI.getVInVoltage();
}
+
+ /**
+ * Define the Vin voltage.
+ *
+ * @param vInVoltage the new voltage
+ */
+ @SuppressWarnings("ParameterName")
public static void setVInVoltage(double vInVoltage) {
RoboRioDataJNI.setVInVoltage(vInVoltage);
}
- public static CallbackStore registerVInCurrentCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the Vin current changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerVInCurrentCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerVInCurrentCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelVInCurrentCallback);
}
+
+ /**
+ * Measure the Vin current.
+ *
+ * @return the Vin current
+ */
public static double getVInCurrent() {
return RoboRioDataJNI.getVInCurrent();
}
+
+ /**
+ * Define the Vin current.
+ *
+ * @param vInCurrent the new current
+ */
+ @SuppressWarnings("ParameterName")
public static void setVInCurrent(double vInCurrent) {
RoboRioDataJNI.setVInCurrent(vInCurrent);
}
- public static CallbackStore registerUserVoltage6VCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 6V rail voltage changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserVoltage6VCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserVoltage6VCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserVoltage6VCallback);
}
+
+ /**
+ * Measure the 6V rail voltage.
+ *
+ * @return the 6V rail voltage
+ */
public static double getUserVoltage6V() {
return RoboRioDataJNI.getUserVoltage6V();
}
+
+ /**
+ * Define the 6V rail voltage.
+ *
+ * @param userVoltage6V the new voltage
+ */
public static void setUserVoltage6V(double userVoltage6V) {
RoboRioDataJNI.setUserVoltage6V(userVoltage6V);
}
- public static CallbackStore registerUserCurrent6VCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 6V rail current changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserCurrent6VCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserCurrent6VCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserCurrent6VCallback);
}
+
+ /**
+ * Measure the 6V rail current.
+ *
+ * @return the 6V rail current
+ */
public static double getUserCurrent6V() {
return RoboRioDataJNI.getUserCurrent6V();
}
+
+ /**
+ * Define the 6V rail current.
+ *
+ * @param userCurrent6V the new current
+ */
public static void setUserCurrent6V(double userCurrent6V) {
RoboRioDataJNI.setUserCurrent6V(userCurrent6V);
}
- public static CallbackStore registerUserActive6VCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 6V rail active state changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserActive6VCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserActive6VCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserActive6VCallback);
}
+
+ /**
+ * Get the 6V rail active state.
+ *
+ * @return true if the 6V rail is active
+ */
public static boolean getUserActive6V() {
return RoboRioDataJNI.getUserActive6V();
}
+
+ /**
+ * Set the 6V rail active state.
+ *
+ * @param userActive6V true to make rail active
+ */
public static void setUserActive6V(boolean userActive6V) {
RoboRioDataJNI.setUserActive6V(userActive6V);
}
- public static CallbackStore registerUserVoltage5VCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 5V rail voltage changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserVoltage5VCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserVoltage5VCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserVoltage5VCallback);
}
+
+ /**
+ * Measure the 5V rail voltage.
+ *
+ * @return the 5V rail voltage
+ */
public static double getUserVoltage5V() {
return RoboRioDataJNI.getUserVoltage5V();
}
+
+ /**
+ * Define the 5V rail voltage.
+ *
+ * @param userVoltage5V the new voltage
+ */
public static void setUserVoltage5V(double userVoltage5V) {
RoboRioDataJNI.setUserVoltage5V(userVoltage5V);
}
- public static CallbackStore registerUserCurrent5VCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 5V rail current changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserCurrent5VCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserCurrent5VCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserCurrent5VCallback);
}
+
+ /**
+ * Measure the 5V rail current.
+ *
+ * @return the 5V rail current
+ */
public static double getUserCurrent5V() {
return RoboRioDataJNI.getUserCurrent5V();
}
+
+ /**
+ * Define the 5V rail current.
+ *
+ * @param userCurrent5V the new current
+ */
public static void setUserCurrent5V(double userCurrent5V) {
RoboRioDataJNI.setUserCurrent5V(userCurrent5V);
}
- public static CallbackStore registerUserActive5VCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 5V rail active state changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserActive5VCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserActive5VCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserActive5VCallback);
}
+
+ /**
+ * Get the 5V rail active state.
+ *
+ * @return true if the 5V rail is active
+ */
public static boolean getUserActive5V() {
return RoboRioDataJNI.getUserActive5V();
}
+
+ /**
+ * Set the 5V rail active state.
+ *
+ * @param userActive5V true to make rail active
+ */
public static void setUserActive5V(boolean userActive5V) {
RoboRioDataJNI.setUserActive5V(userActive5V);
}
- public static CallbackStore registerUserVoltage3V3Callback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 3.3V rail voltage changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserVoltage3V3Callback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserVoltage3V3Callback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserVoltage3V3Callback);
}
+
+ /**
+ * Measure the 3.3V rail voltage.
+ *
+ * @return the 3.3V rail voltage
+ */
public static double getUserVoltage3V3() {
return RoboRioDataJNI.getUserVoltage3V3();
}
+
+ /**
+ * Define the 3.3V rail voltage.
+ *
+ * @param userVoltage3V3 the new voltage
+ */
public static void setUserVoltage3V3(double userVoltage3V3) {
RoboRioDataJNI.setUserVoltage3V3(userVoltage3V3);
}
- public static CallbackStore registerUserCurrent3V3Callback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 3.3V rail current changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserCurrent3V3Callback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserCurrent3V3Callback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserCurrent3V3Callback);
}
+
+ /**
+ * Measure the 3.3V rail current.
+ *
+ * @return the 3.3V rail current
+ */
public static double getUserCurrent3V3() {
return RoboRioDataJNI.getUserCurrent3V3();
}
+
+ /**
+ * Define the 3.3V rail current.
+ *
+ * @param userCurrent3V3 the new current
+ */
public static void setUserCurrent3V3(double userCurrent3V3) {
RoboRioDataJNI.setUserCurrent3V3(userCurrent3V3);
}
- public static CallbackStore registerUserActive3V3Callback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 3.3V rail active state changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserActive3V3Callback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserActive3V3Callback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserActive3V3Callback);
}
+
+ /**
+ * Get the 3.3V rail active state.
+ *
+ * @return true if the 3.3V rail is active
+ */
public static boolean getUserActive3V3() {
return RoboRioDataJNI.getUserActive3V3();
}
+
+ /**
+ * Set the 3.3V rail active state.
+ *
+ * @param userActive3V3 true to make rail active
+ */
public static void setUserActive3V3(boolean userActive3V3) {
RoboRioDataJNI.setUserActive3V3(userActive3V3);
}
- public static CallbackStore registerUserFaults6VCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 6V rail number of faults changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserFaults6VCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserFaults6VCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserFaults6VCallback);
}
+
+ /**
+ * Get the 6V rail number of faults.
+ *
+ * @return number of faults
+ */
public static int getUserFaults6V() {
return RoboRioDataJNI.getUserFaults6V();
}
+
+ /**
+ * Set the 6V rail number of faults.
+ *
+ * @param userFaults6V number of faults
+ */
public static void setUserFaults6V(int userFaults6V) {
RoboRioDataJNI.setUserFaults6V(userFaults6V);
}
- public static CallbackStore registerUserFaults5VCallback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 5V rail number of faults changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserFaults5VCallback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserFaults5VCallback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserFaults5VCallback);
}
+
+ /**
+ * Get the 5V rail number of faults.
+ *
+ * @return number of faults
+ */
public static int getUserFaults5V() {
return RoboRioDataJNI.getUserFaults5V();
}
+
+ /**
+ * Set the 5V rail number of faults.
+ *
+ * @param userFaults5V number of faults
+ */
public static void setUserFaults5V(int userFaults5V) {
RoboRioDataJNI.setUserFaults5V(userFaults5V);
}
- public static CallbackStore registerUserFaults3V3Callback(NotifyCallback callback,
- boolean initialNotify) {
+ /**
+ * Register a callback to be run whenever the 3.3V rail number of faults changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether the callback should be called with the initial value
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerUserFaults3V3Callback(
+ NotifyCallback callback, boolean initialNotify) {
int uid = RoboRioDataJNI.registerUserFaults3V3Callback(callback, initialNotify);
return new CallbackStore(uid, RoboRioDataJNI::cancelUserFaults3V3Callback);
}
+
+ /**
+ * Get the 3.3V rail number of faults.
+ *
+ * @return number of faults
+ */
public static int getUserFaults3V3() {
return RoboRioDataJNI.getUserFaults3V3();
}
+
+ /**
+ * Set the 3.3V rail number of faults.
+ *
+ * @param userFaults3V3 number of faults
+ */
public static void setUserFaults3V3(int userFaults3V3) {
RoboRioDataJNI.setUserFaults3V3(userFaults3V3);
}
+ /**
+ * Register a callback to be run whenever the Brownout voltage changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerBrownoutVoltageCallback(
+ NotifyCallback callback, boolean initialNotify) {
+ int uid = RoboRioDataJNI.registerBrownoutVoltageCallback(callback, initialNotify);
+ return new CallbackStore(uid, RoboRioDataJNI::cancelBrownoutVoltageCallback);
+ }
+
+ /**
+ * Measure the Brownout voltage.
+ *
+ * @return the Brownout voltage
+ */
+ public static double getBrownoutVoltage() {
+ return RoboRioDataJNI.getBrownoutVoltage();
+ }
+
+ /**
+ * Define the Brownout voltage.
+ *
+ * @param vInVoltage the new voltage
+ */
+ @SuppressWarnings("ParameterName")
+ public static void setBrownoutVoltage(double vInVoltage) {
+ RoboRioDataJNI.setBrownoutVoltage(vInVoltage);
+ }
+
+ /** Reset all simulation data. */
public static void resetData() {
RoboRioDataJNI.resetData();
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SPIAccelerometerSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SPIAccelerometerSim.java
index ce6b5c1..da1213a 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SPIAccelerometerSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SPIAccelerometerSim.java
@@ -1,77 +1,184 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.simulation.NotifyCallback;
import edu.wpi.first.hal.simulation.SPIAccelerometerDataJNI;
+/** A class to control a simulated accelerometer over SPI. */
public class SPIAccelerometerSim {
private final int m_index;
+ /**
+ * Construct a new simulation object.
+ *
+ * @param index the HAL index of the accelerometer
+ */
public SPIAccelerometerSim(int index) {
m_index = index;
}
+ /**
+ * Register a callback to be run when this accelerometer activates.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerActiveCallback(NotifyCallback callback, boolean initialNotify) {
int uid = SPIAccelerometerDataJNI.registerActiveCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelActiveCallback);
}
+
+ /**
+ * Check whether the accelerometer is active.
+ *
+ * @return true if active
+ */
public boolean getActive() {
return SPIAccelerometerDataJNI.getActive(m_index);
}
+
+ /**
+ * Define whether this accelerometer is active.
+ *
+ * @param active the new state
+ */
public void setActive(boolean active) {
SPIAccelerometerDataJNI.setActive(m_index, active);
}
+ /**
+ * Register a callback to be run whenever the range changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerRangeCallback(NotifyCallback callback, boolean initialNotify) {
int uid = SPIAccelerometerDataJNI.registerRangeCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelRangeCallback);
}
+
+ /**
+ * Check the range of this accelerometer.
+ *
+ * @return the accelerometer range
+ */
public int getRange() {
return SPIAccelerometerDataJNI.getRange(m_index);
}
+
+ /**
+ * Change the range of this accelerometer.
+ *
+ * @param range the new accelerometer range
+ */
public void setRange(int range) {
SPIAccelerometerDataJNI.setRange(m_index, range);
}
+ /**
+ * Register a callback to be run whenever the X axis value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerXCallback(NotifyCallback callback, boolean initialNotify) {
int uid = SPIAccelerometerDataJNI.registerXCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelXCallback);
}
+
+ /**
+ * Measure the X axis value.
+ *
+ * @return the X axis measurement
+ */
public double getX() {
return SPIAccelerometerDataJNI.getX(m_index);
}
+
+ /**
+ * Change the X axis value of the accelerometer.
+ *
+ * @param x the new reading of the X axis
+ */
+ @SuppressWarnings("ParameterName")
public void setX(double x) {
SPIAccelerometerDataJNI.setX(m_index, x);
}
+ /**
+ * Register a callback to be run whenever the Y axis value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerYCallback(NotifyCallback callback, boolean initialNotify) {
int uid = SPIAccelerometerDataJNI.registerYCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelYCallback);
}
+
+ /**
+ * Measure the Y axis value.
+ *
+ * @return the Y axis measurement
+ */
public double getY() {
return SPIAccelerometerDataJNI.getY(m_index);
}
+
+ /**
+ * Change the Y axis value of the accelerometer.
+ *
+ * @param y the new reading of the Y axis
+ */
+ @SuppressWarnings("ParameterName")
public void setY(double y) {
SPIAccelerometerDataJNI.setY(m_index, y);
}
+ /**
+ * Register a callback to be run whenever the Z axis value changes.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to call the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerZCallback(NotifyCallback callback, boolean initialNotify) {
int uid = SPIAccelerometerDataJNI.registerZCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, SPIAccelerometerDataJNI::cancelZCallback);
}
+
+ /**
+ * Measure the Z axis value.
+ *
+ * @return the Z axis measurement
+ */
public double getZ() {
return SPIAccelerometerDataJNI.getZ(m_index);
}
+
+ /**
+ * Change the Z axis value of the accelerometer.
+ *
+ * @param z the new reading of the Z axis
+ */
+ @SuppressWarnings("ParameterName")
public void setZ(double z) {
SPIAccelerometerDataJNI.setZ(m_index, z);
}
+ /** Reset all simulation data of this object. */
public void resetData() {
SPIAccelerometerDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SPISim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SPISim.java
index 71c197a..6c0b9e9 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SPISim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SPISim.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
@@ -13,39 +10,77 @@
import edu.wpi.first.hal.simulation.SPIDataJNI;
import edu.wpi.first.hal.simulation.SpiReadAutoReceiveBufferCallback;
+/** A class for controlling a simulated SPI device. */
public class SPISim {
private final int m_index;
+ /** Create a new simulated SPI device. */
public SPISim() {
m_index = 0;
}
+ /**
+ * Register a callback to be run when this device is initialized.
+ *
+ * @param callback the callback
+ * @param initialNotify whether to run the callback with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = SPIDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, SPIDataJNI::cancelInitializedCallback);
}
+
+ /**
+ * Check whether this device has been initialized.
+ *
+ * @return true if initialized
+ */
public boolean getInitialized() {
return SPIDataJNI.getInitialized(m_index);
}
+
+ /**
+ * Define whether this device has been initialized.
+ *
+ * @param initialized whether this object is initialized
+ */
public void setInitialized(boolean initialized) {
SPIDataJNI.setInitialized(m_index, initialized);
}
+ /**
+ * Register a callback to be run whenever a `read` operation is executed.
+ *
+ * @param callback the callback
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerReadCallback(BufferCallback callback) {
int uid = SPIDataJNI.registerReadCallback(m_index, callback);
return new CallbackStore(m_index, uid, SPIDataJNI::cancelReadCallback);
}
+ /**
+ * Register a callback to be run whenever a `write` operation is executed.
+ *
+ * @param callback the callback
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
public CallbackStore registerWriteCallback(ConstBufferCallback callback) {
int uid = SPIDataJNI.registerWriteCallback(m_index, callback);
return new CallbackStore(m_index, uid, SPIDataJNI::cancelWriteCallback);
}
- public CallbackStore registerReadAutoReceiveBufferCallback(SpiReadAutoReceiveBufferCallback callback) {
+ public CallbackStore registerReadAutoReceiveBufferCallback(
+ SpiReadAutoReceiveBufferCallback callback) {
int uid = SPIDataJNI.registerReadAutoReceiveBufferCallback(m_index, callback);
return new CallbackStore(m_index, uid, SPIDataJNI::cancelReadAutoReceiveBufferCallback);
}
+ /** Reset all simulation data. */
public void resetData() {
SPIDataJNI.resetData(m_index);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimDeviceSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimDeviceSim.java
index 713c112..bca1f6f 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimDeviceSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimDeviceSim.java
@@ -1,23 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.SimBoolean;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimEnum;
+import edu.wpi.first.hal.SimInt;
+import edu.wpi.first.hal.SimLong;
import edu.wpi.first.hal.SimValue;
import edu.wpi.first.hal.simulation.SimDeviceCallback;
import edu.wpi.first.hal.simulation.SimDeviceDataJNI;
import edu.wpi.first.hal.simulation.SimValueCallback;
-/**
- * Class to control the simulation side of a SimDevice.
- */
+/** Class to control the simulation side of a SimDevice. */
public class SimDeviceSim {
private final int m_handle;
@@ -30,6 +27,33 @@
m_handle = SimDeviceDataJNI.getSimDeviceHandle(name);
}
+ /**
+ * Constructs a SimDeviceSim.
+ *
+ * @param name name of the SimDevice
+ * @param index device index number to append to name
+ */
+ public SimDeviceSim(String name, int index) {
+ this(name + "[" + index + "]");
+ }
+
+ /**
+ * Constructs a SimDeviceSim.
+ *
+ * @param name name of the SimDevice
+ * @param index device index number to append to name
+ * @param channel device channel number to append to name
+ */
+ public SimDeviceSim(String name, int index, int channel) {
+ this(name + "[" + index + "," + channel + "]");
+ }
+
+ /**
+ * Get the property object with the given name.
+ *
+ * @param name the property name
+ * @return the property object
+ */
public SimValue getValue(String name) {
int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
if (handle <= 0) {
@@ -38,6 +62,40 @@
return new SimValue(handle);
}
+ /**
+ * Get the property object with the given name.
+ *
+ * @param name the property name
+ * @return the property object
+ */
+ public SimInt getInt(String name) {
+ int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
+ if (handle <= 0) {
+ return null;
+ }
+ return new SimInt(handle);
+ }
+
+ /**
+ * Get the property object with the given name.
+ *
+ * @param name the property name
+ * @return the property object
+ */
+ public SimLong getLong(String name) {
+ int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
+ if (handle <= 0) {
+ return null;
+ }
+ return new SimLong(handle);
+ }
+
+ /**
+ * Get the property object with the given name.
+ *
+ * @param name the property name
+ * @return the property object
+ */
public SimDouble getDouble(String name) {
int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
if (handle <= 0) {
@@ -46,6 +104,12 @@
return new SimDouble(handle);
}
+ /**
+ * Get the property object with the given name.
+ *
+ * @param name the property name
+ * @return the property object
+ */
public SimEnum getEnum(String name) {
int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
if (handle <= 0) {
@@ -54,6 +118,12 @@
return new SimEnum(handle);
}
+ /**
+ * Get the property object with the given name.
+ *
+ * @param name the property name
+ * @return the property object
+ */
public SimBoolean getBoolean(String name) {
int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
if (handle <= 0) {
@@ -62,42 +132,125 @@
return new SimBoolean(handle);
}
+ /**
+ * Get all options for the given enum.
+ *
+ * @param val the enum
+ * @return names of the different values for that enum
+ */
public static String[] getEnumOptions(SimEnum val) {
return SimDeviceDataJNI.getSimValueEnumOptions(val.getNativeHandle());
}
+ /**
+ * Get all data of this object.
+ *
+ * @return all data and fields of this object
+ */
public SimDeviceDataJNI.SimValueInfo[] enumerateValues() {
return SimDeviceDataJNI.enumerateSimValues(m_handle);
}
+ /**
+ * Get the native handle of this object.
+ *
+ * @return the handle used to refer to this object through JNI
+ */
public int getNativeHandle() {
return m_handle;
}
- public CallbackStore registerValueCreatedCallback(SimValueCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback to be run every time a new value is added to this device.
+ *
+ * @param callback the callback
+ * @param initialNotify should the callback be run with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerValueCreatedCallback(
+ SimValueCallback callback, boolean initialNotify) {
int uid = SimDeviceDataJNI.registerSimValueCreatedCallback(m_handle, callback, initialNotify);
return new CallbackStore(uid, SimDeviceDataJNI::cancelSimValueCreatedCallback);
}
- public CallbackStore registerValueChangedCallback(SimValueCallback callback, boolean initialNotify) {
- int uid = SimDeviceDataJNI.registerSimValueChangedCallback(m_handle, callback, initialNotify);
+ /**
+ * Register a callback to be run every time a value is changed on this device.
+ *
+ * @param value simulated value
+ * @param callback the callback
+ * @param initialNotify should the callback be run with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerValueChangedCallback(
+ SimValue value, SimValueCallback callback, boolean initialNotify) {
+ int uid =
+ SimDeviceDataJNI.registerSimValueChangedCallback(
+ value.getNativeHandle(), callback, initialNotify);
return new CallbackStore(uid, SimDeviceDataJNI::cancelSimValueChangedCallback);
}
+ /**
+ * Register a callback for SimDouble.reset() and similar functions. The callback is called with
+ * the old value.
+ *
+ * @param value simulated value
+ * @param callback callback
+ * @param initialNotify ignored (present for consistency)
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public CallbackStore registerValueResetCallback(
+ SimValue value, SimValueCallback callback, boolean initialNotify) {
+ int uid =
+ SimDeviceDataJNI.registerSimValueResetCallback(
+ value.getNativeHandle(), callback, initialNotify);
+ return new CallbackStore(uid, SimDeviceDataJNI::cancelSimValueResetCallback);
+ }
+
+ /**
+ * Get all sim devices with the given prefix.
+ *
+ * @param prefix the prefix to filter sim devices
+ * @return all sim devices
+ */
public static SimDeviceDataJNI.SimDeviceInfo[] enumerateDevices(String prefix) {
return SimDeviceDataJNI.enumerateSimDevices(prefix);
}
- public static CallbackStore registerDeviceCreatedCallback(String prefix, SimDeviceCallback callback, boolean initialNotify) {
+ /**
+ * Register a callback to be run every time a new {@link edu.wpi.first.hal.SimDevice} is created.
+ *
+ * @param prefix the prefix to filter sim devices
+ * @param callback the callback
+ * @param initialNotify should the callback be run with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerDeviceCreatedCallback(
+ String prefix, SimDeviceCallback callback, boolean initialNotify) {
int uid = SimDeviceDataJNI.registerSimDeviceCreatedCallback(prefix, callback, initialNotify);
return new CallbackStore(uid, SimDeviceDataJNI::cancelSimDeviceCreatedCallback);
}
- public static CallbackStore registerDeviceFreedCallback(String prefix, SimDeviceCallback callback) {
- int uid = SimDeviceDataJNI.registerSimDeviceFreedCallback(prefix, callback);
+ /**
+ * Register a callback to be run every time a {@link edu.wpi.first.hal.SimDevice} is
+ * freed/destroyed.
+ *
+ * @param prefix the prefix to filter sim devices
+ * @param callback the callback
+ * @param initialNotify should the callback be run with the initial state
+ * @return the {@link CallbackStore} object associated with this callback. Save a reference to
+ * this object so GC doesn't cancel the callback.
+ */
+ public static CallbackStore registerDeviceFreedCallback(
+ String prefix, SimDeviceCallback callback, boolean initialNotify) {
+ int uid = SimDeviceDataJNI.registerSimDeviceFreedCallback(prefix, callback, initialNotify);
return new CallbackStore(uid, SimDeviceDataJNI::cancelSimDeviceFreedCallback);
}
+ /** Reset all SimDevice data. */
public static void resetData() {
SimDeviceDataJNI.resetSimDeviceData();
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimHooks.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimHooks.java
index 9c17e1c..1664081 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimHooks.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimHooks.java
@@ -1,18 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
import edu.wpi.first.hal.simulation.SimulatorJNI;
public final class SimHooks {
- private SimHooks() {
- }
+ private SimHooks() {}
+ /**
+ * Override the HAL runtime type (simulated/real).
+ *
+ * @param type runtime type
+ */
public static void setHALRuntimeType(int type) {
SimulatorJNI.setRuntimeType(type);
}
@@ -29,26 +30,44 @@
return SimulatorJNI.getProgramStarted();
}
+ /** Restart the simulator time. */
public static void restartTiming() {
SimulatorJNI.restartTiming();
}
+ /** Pause the simulator time. */
public static void pauseTiming() {
SimulatorJNI.pauseTiming();
}
+ /** Resume the simulator time. */
public static void resumeTiming() {
SimulatorJNI.resumeTiming();
}
+ /**
+ * Check if the simulator time is paused.
+ *
+ * @return true if paused
+ */
public static boolean isTimingPaused() {
return SimulatorJNI.isTimingPaused();
}
+ /**
+ * Advance the simulator time and wait for all notifiers to run.
+ *
+ * @param deltaSeconds the amount to advance (in seconds)
+ */
public static void stepTiming(double deltaSeconds) {
SimulatorJNI.stepTiming((long) (deltaSeconds * 1e6));
}
+ /**
+ * Advance the simulator time and return immediately.
+ *
+ * @param deltaSeconds the amount to advance (in seconds)
+ */
public static void stepTimingAsync(double deltaSeconds) {
SimulatorJNI.stepTimingAsync((long) (deltaSeconds * 1e6));
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SingleJointedArmSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SingleJointedArmSim.java
index f3188a0..87981f7 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SingleJointedArmSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SingleJointedArmSim.java
@@ -1,24 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import edu.wpi.first.wpilibj.system.LinearSystem;
-import edu.wpi.first.wpilibj.system.RungeKutta;
-import edu.wpi.first.wpilibj.system.plant.DCMotor;
-import edu.wpi.first.wpilibj.system.plant.LinearSystemId;
-import edu.wpi.first.wpiutil.math.Matrix;
-import edu.wpi.first.wpiutil.math.VecBuilder;
-import edu.wpi.first.wpiutil.math.numbers.N1;
-import edu.wpi.first.wpiutil.math.numbers.N2;
+import edu.wpi.first.math.Matrix;
+import edu.wpi.first.math.VecBuilder;
+import edu.wpi.first.math.numbers.N1;
+import edu.wpi.first.math.numbers.N2;
+import edu.wpi.first.math.system.LinearSystem;
+import edu.wpi.first.math.system.NumericalIntegration;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.math.system.plant.LinearSystemId;
-/**
- * Represents a simulated single jointed arm mechanism.
- */
+/** Represents a simulated single jointed arm mechanism. */
public class SingleJointedArmSim extends LinearSystemSim<N2, N1, N1> {
// The gearbox for the arm.
private final DCMotor m_gearbox;
@@ -45,39 +40,59 @@
/**
* Creates a simulated arm mechanism.
*
- * @param plant The linear system that represents the arm.
- * @param gearbox The type of and number of motors in the arm gearbox.
- * @param gearing The gearing of the arm (numbers greater than 1 represent reductions).
+ * @param plant The linear system that represents the arm.
+ * @param gearbox The type of and number of motors in the arm gearbox.
+ * @param gearing The gearing of the arm (numbers greater than 1 represent reductions).
* @param armLengthMeters The length of the arm.
- * @param minAngleRads The minimum angle that the arm is capable of.
- * @param maxAngleRads The maximum angle that the arm is capable of.
- * @param armMassKg The mass of the arm.
+ * @param minAngleRads The minimum angle that the arm is capable of.
+ * @param maxAngleRads The maximum angle that the arm is capable of.
+ * @param armMassKg The mass of the arm.
* @param simulateGravity Whether gravity should be simulated or not.
*/
- public SingleJointedArmSim(LinearSystem<N2, N1, N1> plant, DCMotor gearbox, double gearing,
- double armLengthMeters, double minAngleRads, double maxAngleRads,
- double armMassKg, boolean simulateGravity) {
- this(plant, gearbox, gearing, armLengthMeters, minAngleRads, maxAngleRads, armMassKg,
- simulateGravity, null);
+ public SingleJointedArmSim(
+ LinearSystem<N2, N1, N1> plant,
+ DCMotor gearbox,
+ double gearing,
+ double armLengthMeters,
+ double minAngleRads,
+ double maxAngleRads,
+ double armMassKg,
+ boolean simulateGravity) {
+ this(
+ plant,
+ gearbox,
+ gearing,
+ armLengthMeters,
+ minAngleRads,
+ maxAngleRads,
+ armMassKg,
+ simulateGravity,
+ null);
}
/**
* Creates a simulated arm mechanism.
*
- * @param plant The linear system that represents the arm.
- * @param gearbox The type of and number of motors in the arm gearbox.
- * @param gearing The gearing of the arm (numbers greater than 1 represent reductions).
- * @param armLengthMeters The length of the arm.
- * @param minAngleRads The minimum angle that the arm is capable of.
- * @param maxAngleRads The maximum angle that the arm is capable of.
- * @param armMassKg The mass of the arm.
- * @param simulateGravity Whether gravity should be simulated or not.
+ * @param plant The linear system that represents the arm.
+ * @param gearbox The type of and number of motors in the arm gearbox.
+ * @param gearing The gearing of the arm (numbers greater than 1 represent reductions).
+ * @param armLengthMeters The length of the arm.
+ * @param minAngleRads The minimum angle that the arm is capable of.
+ * @param maxAngleRads The maximum angle that the arm is capable of.
+ * @param armMassKg The mass of the arm.
+ * @param simulateGravity Whether gravity should be simulated or not.
* @param measurementStdDevs The standard deviations of the measurements.
*/
- public SingleJointedArmSim(LinearSystem<N2, N1, N1> plant, DCMotor gearbox, double gearing,
- double armLengthMeters, double minAngleRads, double maxAngleRads,
- double armMassKg, boolean simulateGravity,
- Matrix<N1, N1> measurementStdDevs) {
+ public SingleJointedArmSim(
+ LinearSystem<N2, N1, N1> plant,
+ DCMotor gearbox,
+ double gearing,
+ double armLengthMeters,
+ double minAngleRads,
+ double maxAngleRads,
+ double armMassKg,
+ boolean simulateGravity,
+ Matrix<N1, N1> measurementStdDevs) {
super(plant, measurementStdDevs);
m_gearbox = gearbox;
m_gearing = gearing;
@@ -91,40 +106,63 @@
/**
* Creates a simulated arm mechanism.
*
- * @param gearbox The type of and number of motors in the arm gearbox.
- * @param gearing The gearing of the arm (numbers greater than 1 represent reductions).
- * @param jKgMetersSquared The moment of inertia of the arm. This can be calculated from CAD software.
- * @param armLengthMeters The length of the arm.
- * @param minAngleRads The minimum angle that the arm is capable of.
- * @param maxAngleRads The maximum angle that the arm is capable of.
- * @param armMassKg The mass of the arm.
- * @param simulateGravity Whether gravity should be simulated or not.
+ * @param gearbox The type of and number of motors in the arm gearbox.
+ * @param gearing The gearing of the arm (numbers greater than 1 represent reductions).
+ * @param jKgMetersSquared The moment of inertia of the arm, can be calculated from CAD software.
+ * @param armLengthMeters The length of the arm.
+ * @param minAngleRads The minimum angle that the arm is capable of.
+ * @param maxAngleRads The maximum angle that the arm is capable of.
+ * @param armMassKg The mass of the arm.
+ * @param simulateGravity Whether gravity should be simulated or not.
*/
- public SingleJointedArmSim(DCMotor gearbox, double gearing, double jKgMetersSquared,
- double armLengthMeters, double minAngleRads, double maxAngleRads,
- double armMassKg, boolean simulateGravity) {
- this(gearbox, gearing, jKgMetersSquared, armLengthMeters, minAngleRads, maxAngleRads,
- armMassKg, simulateGravity, null);
+ @SuppressWarnings("ParameterName")
+ public SingleJointedArmSim(
+ DCMotor gearbox,
+ double gearing,
+ double jKgMetersSquared,
+ double armLengthMeters,
+ double minAngleRads,
+ double maxAngleRads,
+ double armMassKg,
+ boolean simulateGravity) {
+ this(
+ gearbox,
+ gearing,
+ jKgMetersSquared,
+ armLengthMeters,
+ minAngleRads,
+ maxAngleRads,
+ armMassKg,
+ simulateGravity,
+ null);
}
/**
* Creates a simulated arm mechanism.
*
- * @param gearbox The type of and number of motors in the arm gearbox.
- * @param gearing The gearing of the arm (numbers greater than 1 represent reductions).
- * @param jKgMetersSquared The moment of inertia of the arm. This can be calculated from CAD software.
- * @param armLengthMeters The length of the arm.
- * @param minAngleRads The minimum angle that the arm is capable of.
- * @param maxAngleRads The maximum angle that the arm is capable of.
- * @param armMassKg The mass of the arm.
- * @param simulateGravity Whether gravity should be simulated or not.
+ * @param gearbox The type of and number of motors in the arm gearbox.
+ * @param gearing The gearing of the arm (numbers greater than 1 represent reductions).
+ * @param jKgMetersSquared The moment of inertia of the arm; can be calculated from CAD software.
+ * @param armLengthMeters The length of the arm.
+ * @param minAngleRads The minimum angle that the arm is capable of.
+ * @param maxAngleRads The maximum angle that the arm is capable of.
+ * @param armMassKg The mass of the arm.
+ * @param simulateGravity Whether gravity should be simulated or not.
* @param measurementStdDevs The standard deviations of the measurements.
*/
- public SingleJointedArmSim(DCMotor gearbox, double gearing, double jKgMetersSquared,
- double armLengthMeters, double minAngleRads, double maxAngleRads,
- double armMassKg, boolean simulateGravity,
- Matrix<N1, N1> measurementStdDevs) {
- super(LinearSystemId.createSingleJointedArmSystem(gearbox, jKgMetersSquared, gearing),
+ @SuppressWarnings("ParameterName")
+ public SingleJointedArmSim(
+ DCMotor gearbox,
+ double gearing,
+ double jKgMetersSquared,
+ double armLengthMeters,
+ double minAngleRads,
+ double maxAngleRads,
+ double armMassKg,
+ boolean simulateGravity,
+ Matrix<N1, N1> measurementStdDevs) {
+ super(
+ LinearSystemId.createSingleJointedArmSystem(gearbox, jKgMetersSquared, gearing),
measurementStdDevs);
m_gearbox = gearbox;
m_gearing = gearing;
@@ -136,23 +174,41 @@
}
/**
+ * Returns whether the arm would hit the lower limit.
+ *
+ * @param currentAngleRads The current arm height.
+ * @return Whether the arm would hit the lower limit.
+ */
+ public boolean wouldHitLowerLimit(double currentAngleRads) {
+ return currentAngleRads < this.m_minAngle;
+ }
+
+ /**
+ * Returns whether the arm would hit the upper limit.
+ *
+ * @param currentAngleRads The current arm height.
+ * @return Whether the arm would hit the upper limit.
+ */
+ public boolean wouldHitUpperLimit(double currentAngleRads) {
+ return currentAngleRads > this.m_maxAngle;
+ }
+
+ /**
* Returns whether the arm has hit the lower limit.
*
- * @param x The current arm state.
* @return Whether the arm has hit the lower limit.
*/
- public boolean hasHitLowerLimit(Matrix<N2, N1> x) {
- return x.get(0, 0) < this.m_minAngle;
+ public boolean hasHitLowerLimit() {
+ return wouldHitLowerLimit(getAngleRads());
}
/**
* Returns whether the arm has hit the upper limit.
*
- * @param x The current arm state.
* @return Whether the arm has hit the upper limit.
*/
- public boolean hasHitUpperLimit(Matrix<N2, N1> x) {
- return x.get(0, 0) > this.m_maxAngle;
+ public boolean hasHitUpperLimit() {
+ return wouldHitUpperLimit(getAngleRads());
}
/**
@@ -161,7 +217,7 @@
* @return The current arm angle.
*/
public double getAngleRads() {
- return m_x.get(0, 0);
+ return m_y.get(0, 0);
}
/**
@@ -187,7 +243,7 @@
}
/**
- * Sets the input voltage for the elevator.
+ * Sets the input voltage for the arm.
*
* @param volts The input voltage.
*/
@@ -196,12 +252,10 @@
}
/**
- * Calculates a rough estimate of the moment of inertia of an arm given its
- * length and mass.
+ * Calculates a rough estimate of the moment of inertia of an arm given its length and mass.
*
* @param lengthMeters The length of the arm.
- * @param massKg The mass of the arm.
- *
+ * @param massKg The mass of the arm.
* @return The calculated moment of inertia.
*/
public static double estimateMOI(double lengthMeters, double massKg) {
@@ -212,12 +266,12 @@
* Updates the state of the arm.
*
* @param currentXhat The current state estimate.
- * @param u The system inputs (voltage).
- * @param dtSeconds The time difference between controller updates.
+ * @param u The system inputs (voltage).
+ * @param dtSeconds The time difference between controller updates.
*/
@Override
- protected Matrix<N2, N1> updateX(Matrix<N2, N1> currentXhat,
- Matrix<N1, N1> u, double dtSeconds) {
+ @SuppressWarnings({"ParameterName", "LambdaParameterName"})
+ protected Matrix<N2, N1> updateX(Matrix<N2, N1> currentXhat, Matrix<N1, N1> u, double dtSeconds) {
// Horizontal case:
// Torque = F * r = I * alpha
// alpha = F * r / I
@@ -227,22 +281,33 @@
// This acceleration is added to the linear system dynamics x-dot = Ax + Bu
// We therefore find that f(x, u) = Ax + Bu + [[0] [m * g * r / I *
// cos(theta)]]
- Matrix<N2, N1> updatedXhat = RungeKutta.rungeKutta(
- (Matrix<N2, N1> x, Matrix<N1, N1> u_) -> {
- Matrix<N2, N1> xdot = m_plant.getA().times(x).plus(m_plant.getB().times(u_));
- if (m_simulateGravity) {
- xdot = xdot.plus(VecBuilder.fill(0,
- m_armMass * m_r * -9.8 * 3.0 / (m_armMass * m_r * m_r) * Math.cos(x.get(0, 0))));
- }
- return xdot;
- },
- currentXhat, u, dtSeconds);
+ Matrix<N2, N1> updatedXhat =
+ NumericalIntegration.rkdp(
+ (Matrix<N2, N1> x, Matrix<N1, N1> u_) -> {
+ Matrix<N2, N1> xdot = m_plant.getA().times(x).plus(m_plant.getB().times(u_));
+ if (m_simulateGravity) {
+ xdot =
+ xdot.plus(
+ VecBuilder.fill(
+ 0,
+ m_armMass
+ * m_r
+ * -9.8
+ * 3.0
+ / (m_armMass * m_r * m_r)
+ * Math.cos(x.get(0, 0))));
+ }
+ return xdot;
+ },
+ currentXhat,
+ u,
+ dtSeconds);
// We check for collision after updating xhat
- if (hasHitLowerLimit(updatedXhat)) {
+ if (wouldHitLowerLimit(updatedXhat.get(0, 0))) {
return VecBuilder.fill(m_minAngle, 0);
}
- if (hasHitUpperLimit(updatedXhat)) {
+ if (wouldHitUpperLimit(updatedXhat.get(0, 0))) {
return VecBuilder.fill(m_maxAngle, 0);
}
return updatedXhat;
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/UltrasonicSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/UltrasonicSim.java
new file mode 100644
index 0000000..3781281
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/UltrasonicSim.java
@@ -0,0 +1,38 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import edu.wpi.first.hal.SimBoolean;
+import edu.wpi.first.hal.SimDouble;
+import edu.wpi.first.math.util.Units;
+import edu.wpi.first.wpilibj.Ultrasonic;
+
+public class UltrasonicSim {
+ private final SimBoolean m_simRangeValid;
+ private final SimDouble m_simRange;
+
+ /**
+ * Constructor.
+ *
+ * @param ultrasonic The real ultrasonic to simulate
+ */
+ public UltrasonicSim(Ultrasonic ultrasonic) {
+ SimDeviceSim simDevice = new SimDeviceSim("Ultrasonic", ultrasonic.getEchoChannel());
+ m_simRangeValid = simDevice.getBoolean("Range Valid");
+ m_simRange = simDevice.getDouble("Range (in)");
+ }
+
+ public void setRangeValid(boolean valid) {
+ m_simRangeValid.set(valid);
+ }
+
+ public void setRangeInches(double inches) {
+ m_simRange.set(inches);
+ }
+
+ public void setRangeMeters(double meters) {
+ m_simRange.set(Units.metersToInches(meters));
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/XboxControllerSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/XboxControllerSim.java
index 40a02bf..625ba81 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/XboxControllerSim.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/XboxControllerSim.java
@@ -1,18 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import edu.wpi.first.wpilibj.GenericHID;
import edu.wpi.first.wpilibj.XboxController;
-/**
- * Class to control a simulated Xbox 360 or Xbox One controller.
- */
+/** Class to control a simulated Xbox 360 or Xbox One controller. */
public class XboxControllerSim extends GenericHIDSim {
/**
* Constructs from a XboxController object.
@@ -36,66 +30,146 @@
setButtonCount(10);
}
- public void setX(GenericHID.Hand hand, double value) {
- if (hand.equals(GenericHID.Hand.kLeft)) {
- setRawAxis(XboxController.Axis.kLeftX.value, value);
- } else {
- setRawAxis(XboxController.Axis.kRightX.value, value);
- }
+ /**
+ * Change the left X value of the joystick.
+ *
+ * @param value the new value
+ */
+ public void setLeftX(double value) {
+ setRawAxis(XboxController.Axis.kLeftX.value, value);
}
- public void setY(GenericHID.Hand hand, double value) {
- if (hand.equals(GenericHID.Hand.kLeft)) {
- setRawAxis(XboxController.Axis.kLeftY.value, value);
- } else {
- setRawAxis(XboxController.Axis.kRightY.value, value);
- }
+ /**
+ * Change the right X value of the joystick.
+ *
+ * @param value the new value
+ */
+ public void setRightX(double value) {
+ setRawAxis(XboxController.Axis.kRightX.value, value);
}
- public void setTriggerAxis(GenericHID.Hand hand, double value) {
- if (hand.equals(GenericHID.Hand.kLeft)) {
- setRawAxis(XboxController.Axis.kLeftTrigger.value, value);
- } else {
- setRawAxis(XboxController.Axis.kRightTrigger.value, value);
- }
+ /**
+ * Change the left Y value of the joystick.
+ *
+ * @param value the new value
+ */
+ public void setLeftY(double value) {
+ setRawAxis(XboxController.Axis.kLeftY.value, value);
}
- public void setBumper(GenericHID.Hand hand, boolean state) {
- if (hand.equals(GenericHID.Hand.kLeft)) {
- setRawButton(XboxController.Button.kBumperLeft.value, state);
- } else {
- setRawButton(XboxController.Button.kBumperRight.value, state);
- }
+ /**
+ * Change the right Y value of the joystick.
+ *
+ * @param value the new value
+ */
+ public void setRightY(double value) {
+ setRawAxis(XboxController.Axis.kRightY.value, value);
}
- public void setStickButton(GenericHID.Hand hand, boolean state) {
- if (hand.equals(GenericHID.Hand.kLeft)) {
- setRawButton(XboxController.Button.kStickLeft.value, state);
- } else {
- setRawButton(XboxController.Button.kStickRight.value, state);
- }
+ /**
+ * Change the value of the left trigger axis on the joystick.
+ *
+ * @param value the new value
+ */
+ public void setLeftTriggerAxis(double value) {
+ setRawAxis(XboxController.Axis.kLeftTrigger.value, value);
}
+ /**
+ * Change the value of the right trigger axis on the joystick.
+ *
+ * @param value the new value
+ */
+ public void setRightTriggerAxis(double value) {
+ setRawAxis(XboxController.Axis.kRightTrigger.value, value);
+ }
+
+ /**
+ * Change the value of the left bumper on the joystick.
+ *
+ * @param state the new value
+ */
+ public void setLeftBumper(boolean state) {
+ setRawButton(XboxController.Button.kLeftBumper.value, state);
+ }
+
+ /**
+ * Change the value of the right bumper on the joystick.
+ *
+ * @param state the new value
+ */
+ public void setRightBumper(boolean state) {
+ setRawButton(XboxController.Button.kRightBumper.value, state);
+ }
+
+ /**
+ * Change the value of the left stick button on the joystick.
+ *
+ * @param state the new value
+ */
+ public void setLeftStickButton(boolean state) {
+ setRawButton(XboxController.Button.kLeftStick.value, state);
+ }
+
+ /**
+ * Change the value of the right stick button on the joystick.
+ *
+ * @param state the new value
+ */
+ public void setRightStickButton(boolean state) {
+ setRawButton(XboxController.Button.kRightStick.value, state);
+ }
+
+ /**
+ * Change the value of the A button.
+ *
+ * @param state the new value
+ */
public void setAButton(boolean state) {
setRawButton(XboxController.Button.kA.value, state);
}
+ /**
+ * Change the value of the B button.
+ *
+ * @param state the new value
+ */
public void setBButton(boolean state) {
setRawButton(XboxController.Button.kB.value, state);
}
+ /**
+ * Change the value of the X button.
+ *
+ * @param state the new value
+ */
public void setXButton(boolean state) {
setRawButton(XboxController.Button.kX.value, state);
}
+ /**
+ * Change the value of the Y button.
+ *
+ * @param state the new value
+ */
public void setYButton(boolean state) {
setRawButton(XboxController.Button.kY.value, state);
}
+ /**
+ * Change the value of the Back button.
+ *
+ * @param state the new value
+ */
public void setBackButton(boolean state) {
setRawButton(XboxController.Button.kBack.value, state);
}
+ /**
+ * Change the value of the Start button.
+ *
+ * @param state the new value
+ */
public void setStartButton(boolean state) {
setRawButton(XboxController.Button.kStart.value, state);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/Field2d.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/Field2d.java
new file mode 100644
index 0000000..b76f056
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/Field2d.java
@@ -0,0 +1,119 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.smartdashboard;
+
+import edu.wpi.first.math.geometry.Pose2d;
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.networktables.NTSendable;
+import edu.wpi.first.networktables.NTSendableBuilder;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.util.sendable.SendableRegistry;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 2D representation of game field for dashboards.
+ *
+ * <p>An object's pose is the location shown on the dashboard view. Note that for the robot, this
+ * may or may not match the internal odometry. For example, the robot is shown at a particular
+ * starting location, the pose in this class would represent the actual location on the field, but
+ * the robot's internal state might have a 0,0,0 pose (unless it's initialized to something
+ * different).
+ *
+ * <p>As the user is able to edit the pose, code performing updates should get the robot pose,
+ * transform it as appropriate (e.g. based on wheel odometry), and set the new pose.
+ *
+ * <p>This class provides methods to set the robot pose, but other objects can also be shown by
+ * using the getObject() function. Other objects can also have multiple poses (which will show the
+ * object at multiple locations).
+ */
+public class Field2d implements NTSendable {
+ /** Constructor. */
+ public Field2d() {
+ FieldObject2d obj = new FieldObject2d("Robot");
+ obj.setPose(new Pose2d());
+ m_objects.add(obj);
+ SendableRegistry.add(this, "Field");
+ }
+
+ /**
+ * Set the robot pose from a Pose object.
+ *
+ * @param pose 2D pose
+ */
+ public synchronized void setRobotPose(Pose2d pose) {
+ m_objects.get(0).setPose(pose);
+ }
+
+ /**
+ * Set the robot pose from x, y, and rotation.
+ *
+ * @param xMeters X location, in meters
+ * @param yMeters Y location, in meters
+ * @param rotation rotation
+ */
+ @SuppressWarnings("ParameterName")
+ public synchronized void setRobotPose(double xMeters, double yMeters, Rotation2d rotation) {
+ m_objects.get(0).setPose(xMeters, yMeters, rotation);
+ }
+
+ /**
+ * Get the robot pose.
+ *
+ * @return 2D pose
+ */
+ public synchronized Pose2d getRobotPose() {
+ return m_objects.get(0).getPose();
+ }
+
+ /**
+ * Get or create a field object.
+ *
+ * @param name The field object's name.
+ * @return Field object
+ */
+ public synchronized FieldObject2d getObject(String name) {
+ for (FieldObject2d obj : m_objects) {
+ if (obj.m_name.equals(name)) {
+ return obj;
+ }
+ }
+ FieldObject2d obj = new FieldObject2d(name);
+ m_objects.add(obj);
+ if (m_table != null) {
+ synchronized (obj) {
+ obj.m_entry = m_table.getEntry(name);
+ }
+ }
+ return obj;
+ }
+
+ /**
+ * Get the robot object.
+ *
+ * @return Field object for robot
+ */
+ public synchronized FieldObject2d getRobotObject() {
+ return m_objects.get(0);
+ }
+
+ @Override
+ public void initSendable(NTSendableBuilder builder) {
+ builder.setSmartDashboardType("Field2d");
+
+ synchronized (this) {
+ m_table = builder.getTable();
+ for (FieldObject2d obj : m_objects) {
+ synchronized (obj) {
+ obj.m_entry = m_table.getEntry(obj.m_name);
+ obj.updateEntry(true);
+ }
+ }
+ }
+ }
+
+ private NetworkTable m_table;
+ private final List<FieldObject2d> m_objects = new ArrayList<>();
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/FieldObject2d.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/FieldObject2d.java
new file mode 100644
index 0000000..d6c7a5e
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/FieldObject2d.java
@@ -0,0 +1,198 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.smartdashboard;
+
+import edu.wpi.first.math.geometry.Pose2d;
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.math.geometry.Translation2d;
+import edu.wpi.first.math.trajectory.Trajectory;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Game field object on a Field2d. */
+public class FieldObject2d {
+ /**
+ * Package-local constructor.
+ *
+ * @param name name
+ */
+ FieldObject2d(String name) {
+ m_name = name;
+ }
+
+ /**
+ * Set the pose from a Pose object.
+ *
+ * @param pose 2D pose
+ */
+ public synchronized void setPose(Pose2d pose) {
+ setPoses(pose);
+ }
+
+ /**
+ * Set the pose from x, y, and rotation.
+ *
+ * @param xMeters X location, in meters
+ * @param yMeters Y location, in meters
+ * @param rotation rotation
+ */
+ @SuppressWarnings("ParameterName")
+ public synchronized void setPose(double xMeters, double yMeters, Rotation2d rotation) {
+ setPose(new Pose2d(xMeters, yMeters, rotation));
+ }
+
+ /**
+ * Get the pose.
+ *
+ * @return 2D pose
+ */
+ public synchronized Pose2d getPose() {
+ updateFromEntry();
+ if (m_poses.isEmpty()) {
+ return new Pose2d();
+ }
+ return m_poses.get(0);
+ }
+
+ /**
+ * Set multiple poses from an list of Pose objects. The total number of poses is limited to 85.
+ *
+ * @param poses list of 2D poses
+ */
+ public synchronized void setPoses(List<Pose2d> poses) {
+ m_poses.clear();
+ for (Pose2d pose : poses) {
+ m_poses.add(pose);
+ }
+ updateEntry();
+ }
+
+ /**
+ * Set multiple poses from an list of Pose objects. The total number of poses is limited to 85.
+ *
+ * @param poses list of 2D poses
+ */
+ public synchronized void setPoses(Pose2d... poses) {
+ m_poses.clear();
+ for (Pose2d pose : poses) {
+ m_poses.add(pose);
+ }
+ updateEntry();
+ }
+
+ /**
+ * Sets poses from a trajectory.
+ *
+ * @param trajectory The trajectory from which the poses should be added.
+ */
+ public synchronized void setTrajectory(Trajectory trajectory) {
+ m_poses.clear();
+ for (Trajectory.State state : trajectory.getStates()) {
+ m_poses.add(state.poseMeters);
+ }
+ updateEntry();
+ }
+
+ /**
+ * Get multiple poses.
+ *
+ * @return list of 2D poses
+ */
+ public synchronized List<Pose2d> getPoses() {
+ updateFromEntry();
+ return new ArrayList<Pose2d>(m_poses);
+ }
+
+ void updateEntry() {
+ updateEntry(false);
+ }
+
+ synchronized void updateEntry(boolean setDefault) {
+ if (m_entry == null) {
+ return;
+ }
+
+ if (m_poses.size() < (255 / 3)) {
+ double[] arr = new double[m_poses.size() * 3];
+ int ndx = 0;
+ for (Pose2d pose : m_poses) {
+ Translation2d translation = pose.getTranslation();
+ arr[ndx + 0] = translation.getX();
+ arr[ndx + 1] = translation.getY();
+ arr[ndx + 2] = pose.getRotation().getDegrees();
+ ndx += 3;
+ }
+
+ if (setDefault) {
+ m_entry.setDefaultDoubleArray(arr);
+ } else {
+ m_entry.setDoubleArray(arr);
+ }
+ } else {
+ // send as raw array of doubles if too big for NT array
+ ByteBuffer output = ByteBuffer.allocate(m_poses.size() * 3 * 8);
+ output.order(ByteOrder.BIG_ENDIAN);
+
+ for (Pose2d pose : m_poses) {
+ Translation2d translation = pose.getTranslation();
+ output.putDouble(translation.getX());
+ output.putDouble(translation.getY());
+ output.putDouble(pose.getRotation().getDegrees());
+ }
+
+ if (setDefault) {
+ m_entry.setDefaultRaw(output.array());
+ } else {
+ m_entry.forceSetRaw(output.array());
+ }
+ }
+ }
+
+ private synchronized void updateFromEntry() {
+ if (m_entry == null) {
+ return;
+ }
+
+ double[] arr = m_entry.getDoubleArray((double[]) null);
+ if (arr != null) {
+ if ((arr.length % 3) != 0) {
+ return;
+ }
+
+ m_poses.clear();
+ for (int i = 0; i < arr.length; i += 3) {
+ m_poses.add(new Pose2d(arr[i], arr[i + 1], Rotation2d.fromDegrees(arr[i + 2])));
+ }
+ } else {
+ // read as raw array of doubles
+ byte[] data = m_entry.getRaw((byte[]) null);
+ if (data == null) {
+ return;
+ }
+
+ // must be triples of doubles
+ if ((data.length % (3 * 8)) != 0) {
+ return;
+ }
+ ByteBuffer input = ByteBuffer.wrap(data);
+ input.order(ByteOrder.BIG_ENDIAN);
+
+ m_poses.clear();
+ for (int i = 0; i < (data.length / (3 * 8)); i++) {
+ double x = input.getDouble();
+ double y = input.getDouble();
+ double rot = input.getDouble();
+ m_poses.add(new Pose2d(x, y, Rotation2d.fromDegrees(rot)));
+ }
+ }
+ }
+
+ String m_name;
+ NetworkTableEntry m_entry;
+ private final List<Pose2d> m_poses = new ArrayList<>();
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/ListenerExecutor.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/ListenerExecutor.java
index 274c7a8..19a3fc1 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/ListenerExecutor.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/ListenerExecutor.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.smartdashboard;
@@ -31,9 +28,7 @@
}
}
- /**
- * Runs all posted tasks. Called periodically from main thread.
- */
+ /** Runs all posted tasks. Called periodically from main thread. */
public void runListenerTasks() {
// Locally copy tasks from internal list; minimizes blocking time
Collection<Runnable> tasks = new ArrayList<>();
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/Mechanism2d.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/Mechanism2d.java
new file mode 100644
index 0000000..8967944
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/Mechanism2d.java
@@ -0,0 +1,113 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.smartdashboard;
+
+import edu.wpi.first.networktables.NTSendable;
+import edu.wpi.first.networktables.NTSendableBuilder;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.wpilibj.util.Color8Bit;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Visual 2D representation of arms, elevators, and general mechanisms through a node-based API.
+ *
+ * <p>A Mechanism2d object is published and contains at least one root node. A root is the anchor
+ * point of other nodes (such as ligaments). Other nodes are recursively appended based on other
+ * nodes.
+ *
+ * @see MechanismObject2d
+ * @see MechanismLigament2d
+ * @see MechanismRoot2d
+ */
+public final class Mechanism2d implements NTSendable {
+ private static final String kBackgroundColor = "backgroundColor";
+ private NetworkTable m_table;
+ private final Map<String, MechanismRoot2d> m_roots;
+ private final double[] m_dims = new double[2];
+ private String m_color;
+
+ /**
+ * Create a new Mechanism2d with the given dimensions and default color (dark blue).
+ *
+ * <p>The dimensions represent the canvas that all the nodes are drawn on.
+ *
+ * @param width the width
+ * @param height the height
+ */
+ public Mechanism2d(double width, double height) {
+ this(width, height, new Color8Bit(0, 0, 32));
+ }
+
+ /**
+ * Create a new Mechanism2d with the given dimensions.
+ *
+ * <p>The dimensions represent the canvas that all the nodes are drawn on.
+ *
+ * @param width the width
+ * @param height the height
+ * @param backgroundColor the background color. Defaults to dark blue.
+ */
+ public Mechanism2d(double width, double height, Color8Bit backgroundColor) {
+ m_roots = new HashMap<>();
+ m_dims[0] = width;
+ m_dims[1] = height;
+ setBackgroundColor(backgroundColor);
+ }
+
+ /**
+ * Get or create a root in this Mechanism2d with the given name and position.
+ *
+ * <p>If a root with the given name already exists, the given x and y coordinates are not used.
+ *
+ * @param name the root name
+ * @param x the root x coordinate
+ * @param y the root y coordinate
+ * @return a new root joint object, or the existing one with the given name.
+ */
+ public synchronized MechanismRoot2d getRoot(String name, double x, double y) {
+ var existing = m_roots.get(name);
+ if (existing != null) {
+ return existing;
+ }
+
+ var root = new MechanismRoot2d(name, x, y);
+ m_roots.put(name, root);
+ if (m_table != null) {
+ root.update(m_table.getSubTable(name));
+ }
+ return root;
+ }
+
+ /**
+ * Set the Mechanism2d background color.
+ *
+ * @param color the new color
+ */
+ public synchronized void setBackgroundColor(Color8Bit color) {
+ this.m_color = String.format("#%02X%02X%02X", color.red, color.green, color.blue);
+ if (m_table != null) {
+ m_table.getEntry(kBackgroundColor).setString(m_color);
+ }
+ }
+
+ @Override
+ public void initSendable(NTSendableBuilder builder) {
+ builder.setSmartDashboardType("Mechanism2d");
+ synchronized (this) {
+ m_table = builder.getTable();
+ m_table.getEntry("dims").setDoubleArray(m_dims);
+ m_table.getEntry(kBackgroundColor).setString(m_color);
+ for (Entry<String, MechanismRoot2d> entry : m_roots.entrySet()) {
+ String name = entry.getKey();
+ MechanismRoot2d root = entry.getValue();
+ synchronized (root) {
+ root.update(m_table.getSubTable(name));
+ }
+ }
+ }
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismLigament2d.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismLigament2d.java
new file mode 100644
index 0000000..8579936
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismLigament2d.java
@@ -0,0 +1,155 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.smartdashboard;
+
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.wpilibj.util.Color8Bit;
+
+/**
+ * Ligament node on a Mechanism2d. A ligament can have its length changed (like an elevator) or
+ * angle changed, like an arm.
+ *
+ * @see Mechanism2d
+ */
+public class MechanismLigament2d extends MechanismObject2d {
+ private double m_angle;
+ private NetworkTableEntry m_angleEntry;
+ private String m_color;
+ private NetworkTableEntry m_colorEntry;
+ private double m_length;
+ private NetworkTableEntry m_lengthEntry;
+ private double m_weight;
+ private NetworkTableEntry m_weightEntry;
+
+ /**
+ * Create a new ligament.
+ *
+ * @param name The ligament name.
+ * @param length The ligament length.
+ * @param angle The ligament angle.
+ * @param lineWidth The ligament's line width.
+ * @param color The ligament's color.
+ */
+ public MechanismLigament2d(
+ String name, double length, double angle, double lineWidth, Color8Bit color) {
+ super(name);
+ setColor(color);
+ setLength(length);
+ setAngle(angle);
+ setLineWeight(lineWidth);
+ }
+
+ /**
+ * Create a new ligament with the default color (orange) and thickness (6).
+ *
+ * @param name The ligament's name.
+ * @param length The ligament's length.
+ * @param angle The ligament's angle relative to its parent.
+ */
+ public MechanismLigament2d(String name, double length, double angle) {
+ this(name, length, angle, 10, new Color8Bit(235, 137, 52));
+ }
+
+ /**
+ * Set the ligament's angle relative to its parent.
+ *
+ * @param degrees the angle, in degrees
+ */
+ public synchronized void setAngle(double degrees) {
+ m_angle = degrees;
+ flush();
+ }
+
+ /**
+ * Set the ligament's angle relative to its parent.
+ *
+ * @param angle the angle
+ */
+ public synchronized void setAngle(Rotation2d angle) {
+ setAngle(angle.getDegrees());
+ }
+
+ /**
+ * Get the ligament's angle relative to its parent.
+ *
+ * @return the angle, in degrees
+ */
+ public synchronized double getAngle() {
+ if (m_angleEntry != null) {
+ m_angle = m_angleEntry.getDouble(0.0);
+ }
+ return m_angle;
+ }
+
+ /**
+ * Set the ligament's length.
+ *
+ * @param length the line length
+ */
+ public synchronized void setLength(double length) {
+ m_length = length;
+ flush();
+ }
+
+ /**
+ * Get the ligament length.
+ *
+ * @return the line length
+ */
+ public synchronized double getLength() {
+ if (m_lengthEntry != null) {
+ m_length = m_lengthEntry.getDouble(0.0);
+ }
+ return m_length;
+ }
+
+ /**
+ * Set the ligament color.
+ *
+ * @param color the color of the line
+ */
+ public synchronized void setColor(Color8Bit color) {
+ m_color = String.format("#%02X%02X%02X", color.red, color.green, color.blue);
+ flush();
+ }
+
+ /**
+ * Set the line thickness.
+ *
+ * @param weight the line thickness
+ */
+ public synchronized void setLineWeight(double weight) {
+ m_weight = weight;
+ flush();
+ }
+
+ @Override
+ protected synchronized void updateEntries(NetworkTable table) {
+ table.getEntry(".type").setString("line");
+ m_angleEntry = table.getEntry("angle");
+ m_lengthEntry = table.getEntry("length");
+ m_colorEntry = table.getEntry("color");
+ m_weightEntry = table.getEntry("weight");
+ flush();
+ }
+
+ /** Flush latest data to NT. */
+ private synchronized void flush() {
+ if (m_angleEntry != null) {
+ m_angleEntry.setDouble(m_angle);
+ }
+ if (m_lengthEntry != null) {
+ m_lengthEntry.setDouble(m_length);
+ }
+ if (m_colorEntry != null) {
+ m_colorEntry.setString(m_color);
+ }
+ if (m_weightEntry != null) {
+ m_weightEntry.setDouble(m_weight);
+ }
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismObject2d.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismObject2d.java
new file mode 100644
index 0000000..4598f7e
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismObject2d.java
@@ -0,0 +1,73 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.smartdashboard;
+
+import edu.wpi.first.networktables.NetworkTable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Common base class for all Mechanism2d node types.
+ *
+ * <p>To append another node, call {@link #append(MechanismObject2d)}. Objects that aren't appended
+ * to a published {@link Mechanism2d} container are nonfunctional.
+ *
+ * @see Mechanism2d
+ */
+public abstract class MechanismObject2d {
+ /** Relative to parent. */
+ private final String m_name;
+
+ private NetworkTable m_table;
+ private final Map<String, MechanismObject2d> m_objects = new HashMap<>(1);
+
+ /**
+ * Create a new Mechanism node object.
+ *
+ * @param name the node's name, must be unique.
+ */
+ protected MechanismObject2d(String name) {
+ m_name = name;
+ }
+
+ /**
+ * Append a Mechanism object that is based on this one.
+ *
+ * @param <T> The object type.
+ * @param object the object to add.
+ * @return the object given as a parameter, useful for variable assignments and call chaining.
+ * @throws UnsupportedOperationException if the object's name is already used - object names must
+ * be unique.
+ */
+ public final synchronized <T extends MechanismObject2d> T append(T object) {
+ if (m_objects.containsKey(object.getName())) {
+ throw new UnsupportedOperationException("Mechanism object names must be unique!");
+ }
+ m_objects.put(object.getName(), object);
+ if (m_table != null) {
+ object.update(m_table.getSubTable(object.getName()));
+ }
+ return object;
+ }
+
+ final void update(NetworkTable table) {
+ m_table = table;
+ updateEntries(m_table);
+ for (MechanismObject2d obj : m_objects.values()) {
+ obj.update(m_table.getSubTable(obj.m_name));
+ }
+ }
+
+ /**
+ * Update all entries with new ones from a new table.
+ *
+ * @param table the new table.
+ */
+ protected abstract void updateEntries(NetworkTable table);
+
+ public final String getName() {
+ return m_name;
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismRoot2d.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismRoot2d.java
new file mode 100644
index 0000000..39f4515
--- /dev/null
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismRoot2d.java
@@ -0,0 +1,97 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.smartdashboard;
+
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Root Mechanism2d node.
+ *
+ * <p>A root is the anchor point of other nodes (such as ligaments).
+ *
+ * <p>Do not create objects of this class directly! Obtain instances from the {@link
+ * Mechanism2d#getRoot(String, double, double)} factory method.
+ *
+ * <p>Append other nodes by using {@link #append(MechanismObject2d)}.
+ */
+public final class MechanismRoot2d {
+ private final String m_name;
+ private NetworkTable m_table;
+ private final Map<String, MechanismObject2d> m_objects = new HashMap<>(1);
+ private double m_x;
+ private NetworkTableEntry m_xEntry;
+ private double m_y;
+ private NetworkTableEntry m_yEntry;
+
+ /**
+ * Package-private constructor for roots.
+ *
+ * @param name name
+ * @param x x coordinate of root (provide only when constructing a root node)
+ * @param y y coordinate of root (provide only when constructing a root node)
+ */
+ MechanismRoot2d(String name, double x, double y) {
+ m_name = name;
+ m_x = x;
+ m_y = y;
+ }
+
+ /**
+ * Append a Mechanism object that is based on this one.
+ *
+ * @param <T> The object type.
+ * @param object the object to add.
+ * @return the object given as a parameter, useful for variable assignments and call chaining.
+ * @throws UnsupportedOperationException if the object's name is already used - object names must
+ * be unique.
+ */
+ public synchronized <T extends MechanismObject2d> T append(T object) {
+ if (m_objects.containsKey(object.getName())) {
+ throw new UnsupportedOperationException("Mechanism object names must be unique!");
+ }
+ m_objects.put(object.getName(), object);
+ if (m_table != null) {
+ object.update(m_table.getSubTable(object.getName()));
+ }
+ return object;
+ }
+
+ /**
+ * Set the root's position.
+ *
+ * @param x new x coordinate
+ * @param y new y coordinate
+ */
+ public synchronized void setPosition(double x, double y) {
+ m_x = x;
+ m_y = y;
+ }
+
+ synchronized void update(NetworkTable table) {
+ m_table = table;
+ m_xEntry = m_table.getEntry("x");
+ m_yEntry = m_table.getEntry("y");
+ flush();
+ for (MechanismObject2d obj : m_objects.values()) {
+ obj.update(m_table.getSubTable(obj.getName()));
+ }
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ private synchronized void flush() {
+ if (m_xEntry != null) {
+ m_xEntry.setDouble(m_x);
+ }
+ if (m_yEntry != null) {
+ m_yEntry.setDouble(m_y);
+ }
+ }
+}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilder.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilder.java
deleted file mode 100644
index 35a8b54..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilder.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.smartdashboard;
-
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-import java.util.function.DoubleConsumer;
-import java.util.function.DoubleSupplier;
-import java.util.function.Supplier;
-
-import edu.wpi.first.networktables.NetworkTableEntry;
-import edu.wpi.first.networktables.NetworkTableValue;
-
-public interface SendableBuilder {
- /**
- * Set the string representation of the named data type that will be used
- * by the smart dashboard for this sendable.
- *
- * @param type data type
- */
- void setSmartDashboardType(String type);
-
- /**
- * Set a flag indicating if this sendable should be treated as an actuator.
- * By default this flag is false.
- *
- * @param value true if actuator, false if not
- */
- void setActuator(boolean value);
-
- /**
- * Set the function that should be called to set the Sendable into a safe
- * state. This is called when entering and exiting Live Window mode.
- *
- * @param func function
- */
- void setSafeState(Runnable func);
-
- /**
- * Set the function that should be called to update the network table
- * for things other than properties. Note this function is not passed
- * the network table object; instead it should use the entry handles
- * returned by getEntry().
- *
- * @param func function
- */
- void setUpdateTable(Runnable func);
-
- /**
- * Add a property without getters or setters. This can be used to get
- * entry handles for the function called by setUpdateTable().
- *
- * @param key property name
- * @return Network table entry
- */
- NetworkTableEntry getEntry(String key);
-
- /**
- * Represents an operation that accepts a single boolean-valued argument and
- * returns no result. This is the primitive type specialization of Consumer
- * for boolean. Unlike most other functional interfaces, BooleanConsumer is
- * expected to operate via side-effects.
- *
- * <p>This is a functional interface whose functional method is accept(boolean).
- */
- @FunctionalInterface
- interface BooleanConsumer {
- /**
- * Performs the operation on the given value.
- * @param value the value
- */
- void accept(boolean value);
- }
-
- /**
- * Add a boolean property.
- *
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
- */
- void addBooleanProperty(String key, BooleanSupplier getter, BooleanConsumer setter);
-
- /**
- * Add a double property.
- *
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
- */
- void addDoubleProperty(String key, DoubleSupplier getter, DoubleConsumer setter);
-
- /**
- * Add a string property.
- *
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
- */
- void addStringProperty(String key, Supplier<String> getter, Consumer<String> setter);
-
- /**
- * Add a boolean array property.
- *
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
- */
- void addBooleanArrayProperty(String key, Supplier<boolean[]> getter, Consumer<boolean[]> setter);
-
- /**
- * Add a double array property.
- *
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
- */
- void addDoubleArrayProperty(String key, Supplier<double[]> getter, Consumer<double[]> setter);
-
- /**
- * Add a string array property.
- *
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
- */
- void addStringArrayProperty(String key, Supplier<String[]> getter, Consumer<String[]> setter);
-
- /**
- * Add a raw property.
- *
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
- */
- void addRawProperty(String key, Supplier<byte[]> getter, Consumer<byte[]> setter);
-
- /**
- * Add a NetworkTableValue property.
- *
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
- */
- void addValueProperty(String key, Supplier<NetworkTableValue> getter,
- Consumer<NetworkTableValue> setter);
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilderImpl.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilderImpl.java
index a82f26b..6c07fe3 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilderImpl.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableBuilderImpl.java
@@ -1,12 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.smartdashboard;
+import edu.wpi.first.networktables.EntryListenerFlags;
+import edu.wpi.first.networktables.NTSendableBuilder;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableValue;
+import edu.wpi.first.util.function.BooleanConsumer;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BooleanSupplier;
@@ -16,12 +19,7 @@
import java.util.function.Function;
import java.util.function.Supplier;
-import edu.wpi.first.networktables.EntryListenerFlags;
-import edu.wpi.first.networktables.NetworkTable;
-import edu.wpi.first.networktables.NetworkTableEntry;
-import edu.wpi.first.networktables.NetworkTableValue;
-
-public class SendableBuilderImpl implements SendableBuilder {
+public class SendableBuilderImpl implements NTSendableBuilder {
private static class Property {
Property(NetworkTable table, String key) {
m_entry = table.getEntry(key);
@@ -60,7 +58,7 @@
private boolean m_actuator;
/**
- * Set the network table. Must be called prior to any Add* functions being called.
+ * Set the network table. Must be called prior to any Add* functions being called.
*
* @param table Network table
*/
@@ -74,15 +72,18 @@
*
* @return The network table
*/
+ @Override
public NetworkTable getTable() {
return m_table;
}
/**
* Return whether this sendable has an associated table.
+ *
* @return True if it has a table, false if not.
*/
- public boolean hasTable() {
+ @Override
+ public boolean isPublished() {
return m_table != null;
}
@@ -95,10 +96,9 @@
return m_actuator;
}
- /**
- * Update the network table values by calling the getters for all properties.
- */
- public void updateTable() {
+ /** Update the network table values by calling the getters for all properties. */
+ @Override
+ public void update() {
for (Property property : m_properties) {
if (property.m_update != null) {
property.m_update.accept(property.m_entry);
@@ -109,9 +109,7 @@
}
}
- /**
- * Hook setters for all properties.
- */
+ /** Hook setters for all properties. */
public void startListeners() {
for (Property property : m_properties) {
property.startListener();
@@ -121,9 +119,7 @@
}
}
- /**
- * Unhook setters for all properties.
- */
+ /** Unhook setters for all properties. */
public void stopListeners() {
for (Property property : m_properties) {
property.stopListener();
@@ -134,7 +130,7 @@
}
/**
- * Start LiveWindow mode by hooking the setters for all properties. Also calls the safeState
+ * Start LiveWindow mode by hooking the setters for all properties. Also calls the safeState
* function if one was provided.
*/
public void startLiveWindowMode() {
@@ -145,7 +141,7 @@
}
/**
- * Stop LiveWindow mode by unhooking the setters for all properties. Also calls the safeState
+ * Stop LiveWindow mode by unhooking the setters for all properties. Also calls the safeState
* function if one was provided.
*/
public void stopLiveWindowMode() {
@@ -155,9 +151,8 @@
}
}
- /**
- * Clear properties.
- */
+ /** Clear properties. */
+ @Override
public void clearProperties() {
stopListeners();
m_properties.clear();
@@ -187,7 +182,7 @@
}
/**
- * Set the function that should be called to set the Sendable into a safe state. This is called
+ * Set the function that should be called to set the Sendable into a safe state. This is called
* when entering and exiting Live Window mode.
*
* @param func function
@@ -199,7 +194,7 @@
/**
* Set the function that should be called to update the network table for things other than
- * properties. Note this function is not passed the network table object; instead it should use
+ * properties. Note this function is not passed the network table object; instead it should use
* the entry handles returned by getEntry().
*
* @param func function
@@ -210,7 +205,7 @@
}
/**
- * Add a property without getters or setters. This can be used to get entry handles for the
+ * Add a property without getters or setters. This can be used to get entry handles for the
* function called by setUpdateTable().
*
* @param key property name
@@ -224,7 +219,7 @@
/**
* Add a boolean property.
*
- * @param key property name
+ * @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@@ -235,11 +230,18 @@
property.m_update = entry -> entry.setBoolean(getter.getAsBoolean());
}
if (setter != null) {
- property.m_createListener = entry -> entry.addListener(event -> {
- if (event.value.isBoolean()) {
- SmartDashboard.postListenerTask(() -> setter.accept(event.value.getBoolean()));
- }
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+ property.m_createListener =
+ entry ->
+ entry.addListener(
+ event -> {
+ if (event.value.isBoolean()) {
+ SmartDashboard.postListenerTask(
+ () -> setter.accept(event.value.getBoolean()));
+ }
+ },
+ EntryListenerFlags.kImmediate
+ | EntryListenerFlags.kNew
+ | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
@@ -247,7 +249,7 @@
/**
* Add a double property.
*
- * @param key property name
+ * @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@@ -258,11 +260,17 @@
property.m_update = entry -> entry.setDouble(getter.getAsDouble());
}
if (setter != null) {
- property.m_createListener = entry -> entry.addListener(event -> {
- if (event.value.isDouble()) {
- SmartDashboard.postListenerTask(() -> setter.accept(event.value.getDouble()));
- }
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+ property.m_createListener =
+ entry ->
+ entry.addListener(
+ event -> {
+ if (event.value.isDouble()) {
+ SmartDashboard.postListenerTask(() -> setter.accept(event.value.getDouble()));
+ }
+ },
+ EntryListenerFlags.kImmediate
+ | EntryListenerFlags.kNew
+ | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
@@ -270,7 +278,7 @@
/**
* Add a string property.
*
- * @param key property name
+ * @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@@ -281,11 +289,17 @@
property.m_update = entry -> entry.setString(getter.get());
}
if (setter != null) {
- property.m_createListener = entry -> entry.addListener(event -> {
- if (event.value.isString()) {
- SmartDashboard.postListenerTask(() -> setter.accept(event.value.getString()));
- }
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+ property.m_createListener =
+ entry ->
+ entry.addListener(
+ event -> {
+ if (event.value.isString()) {
+ SmartDashboard.postListenerTask(() -> setter.accept(event.value.getString()));
+ }
+ },
+ EntryListenerFlags.kImmediate
+ | EntryListenerFlags.kNew
+ | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
@@ -293,23 +307,30 @@
/**
* Add a boolean array property.
*
- * @param key property name
+ * @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
- public void addBooleanArrayProperty(String key, Supplier<boolean[]> getter,
- Consumer<boolean[]> setter) {
+ public void addBooleanArrayProperty(
+ String key, Supplier<boolean[]> getter, Consumer<boolean[]> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = entry -> entry.setBooleanArray(getter.get());
}
if (setter != null) {
- property.m_createListener = entry -> entry.addListener(event -> {
- if (event.value.isBooleanArray()) {
- SmartDashboard.postListenerTask(() -> setter.accept(event.value.getBooleanArray()));
- }
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+ property.m_createListener =
+ entry ->
+ entry.addListener(
+ event -> {
+ if (event.value.isBooleanArray()) {
+ SmartDashboard.postListenerTask(
+ () -> setter.accept(event.value.getBooleanArray()));
+ }
+ },
+ EntryListenerFlags.kImmediate
+ | EntryListenerFlags.kNew
+ | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
@@ -317,23 +338,30 @@
/**
* Add a double array property.
*
- * @param key property name
+ * @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
- public void addDoubleArrayProperty(String key, Supplier<double[]> getter,
- Consumer<double[]> setter) {
+ public void addDoubleArrayProperty(
+ String key, Supplier<double[]> getter, Consumer<double[]> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = entry -> entry.setDoubleArray(getter.get());
}
if (setter != null) {
- property.m_createListener = entry -> entry.addListener(event -> {
- if (event.value.isDoubleArray()) {
- SmartDashboard.postListenerTask(() -> setter.accept(event.value.getDoubleArray()));
- }
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+ property.m_createListener =
+ entry ->
+ entry.addListener(
+ event -> {
+ if (event.value.isDoubleArray()) {
+ SmartDashboard.postListenerTask(
+ () -> setter.accept(event.value.getDoubleArray()));
+ }
+ },
+ EntryListenerFlags.kImmediate
+ | EntryListenerFlags.kNew
+ | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
@@ -341,23 +369,30 @@
/**
* Add a string array property.
*
- * @param key property name
+ * @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
- public void addStringArrayProperty(String key, Supplier<String[]> getter,
- Consumer<String[]> setter) {
+ public void addStringArrayProperty(
+ String key, Supplier<String[]> getter, Consumer<String[]> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = entry -> entry.setStringArray(getter.get());
}
if (setter != null) {
- property.m_createListener = entry -> entry.addListener(event -> {
- if (event.value.isStringArray()) {
- SmartDashboard.postListenerTask(() -> setter.accept(event.value.getStringArray()));
- }
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+ property.m_createListener =
+ entry ->
+ entry.addListener(
+ event -> {
+ if (event.value.isStringArray()) {
+ SmartDashboard.postListenerTask(
+ () -> setter.accept(event.value.getStringArray()));
+ }
+ },
+ EntryListenerFlags.kImmediate
+ | EntryListenerFlags.kNew
+ | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
@@ -365,7 +400,7 @@
/**
* Add a raw property.
*
- * @param key property name
+ * @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@@ -376,11 +411,17 @@
property.m_update = entry -> entry.setRaw(getter.get());
}
if (setter != null) {
- property.m_createListener = entry -> entry.addListener(event -> {
- if (event.value.isRaw()) {
- SmartDashboard.postListenerTask(() -> setter.accept(event.value.getRaw()));
- }
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+ property.m_createListener =
+ entry ->
+ entry.addListener(
+ event -> {
+ if (event.value.isRaw()) {
+ SmartDashboard.postListenerTask(() -> setter.accept(event.value.getRaw()));
+ }
+ },
+ EntryListenerFlags.kImmediate
+ | EntryListenerFlags.kNew
+ | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
@@ -388,21 +429,27 @@
/**
* Add a NetworkTableValue property.
*
- * @param key property name
+ * @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
- public void addValueProperty(String key, Supplier<NetworkTableValue> getter,
- Consumer<NetworkTableValue> setter) {
+ public void addValueProperty(
+ String key, Supplier<NetworkTableValue> getter, Consumer<NetworkTableValue> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = entry -> entry.setValue(getter.get());
}
if (setter != null) {
- property.m_createListener = entry -> entry.addListener(event -> {
- SmartDashboard.postListenerTask(() -> setter.accept(event.value));
- }, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
+ property.m_createListener =
+ entry ->
+ entry.addListener(
+ event -> {
+ SmartDashboard.postListenerTask(() -> setter.accept(event.value));
+ },
+ EntryListenerFlags.kImmediate
+ | EntryListenerFlags.kNew
+ | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java
index cdf1ffb..2614edf 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java
@@ -1,12 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.smartdashboard;
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+
+import edu.wpi.first.networktables.NTSendable;
+import edu.wpi.first.networktables.NTSendableBuilder;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.util.sendable.SendableRegistry;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -14,11 +17,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
-import edu.wpi.first.networktables.NetworkTableEntry;
-import edu.wpi.first.wpilibj.Sendable;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
-
/**
* The {@link SendableChooser} class is a useful tool for presenting a selection of options to the
* {@link SmartDashboard}.
@@ -31,38 +29,25 @@
*
* @param <V> The type of the values to be stored
*/
-public class SendableChooser<V> implements Sendable, AutoCloseable {
- /**
- * The key for the default value.
- */
+public class SendableChooser<V> implements NTSendable, AutoCloseable {
+ /** The key for the default value. */
private static final String DEFAULT = "default";
- /**
- * The key for the selected option.
- */
+ /** The key for the selected option. */
private static final String SELECTED = "selected";
- /**
- * The key for the active option.
- */
+ /** The key for the active option. */
private static final String ACTIVE = "active";
- /**
- * The key for the option array.
- */
+ /** The key for the option array. */
private static final String OPTIONS = "options";
- /**
- * The key for the instance number.
- */
+ /** The key for the instance number. */
private static final String INSTANCE = ".instance";
- /**
- * A map linking strings to the objects the represent.
- */
+ /** A map linking strings to the objects the represent. */
private final Map<String, V> m_map = new LinkedHashMap<>();
+
private String m_defaultChoice = "";
private final int m_instance;
private static final AtomicInteger s_instances = new AtomicInteger();
- /**
- * Instantiates a {@link SendableChooser}.
- */
+ /** Instantiates a {@link SendableChooser}. */
public SendableChooser() {
m_instance = s_instances.getAndIncrement();
SendableRegistry.add(this, "SendableChooser", m_instance);
@@ -77,7 +62,7 @@
* Adds the given object to the list of options. On the {@link SmartDashboard} on the desktop, the
* object will appear as the given name.
*
- * @param name the name of the option
+ * @param name the name of the option
* @param object the option
*/
public void addOption(String name, V object) {
@@ -88,8 +73,7 @@
* Adds the given object to the list of options.
*
* @deprecated Use {@link #addOption(String, Object)} instead.
- *
- * @param name the name of the option
+ * @param name the name of the option
* @param object the option
*/
@Deprecated
@@ -102,7 +86,7 @@
* very close to {@link #addOption(String, Object)} except that it will use this as the default
* option if none other is explicitly selected.
*
- * @param name the name of the option
+ * @param name the name of the option
* @param object the option
*/
public void setDefaultOption(String name, V object) {
@@ -116,8 +100,7 @@
* Adds the given object to the list of options and marks it as the default.
*
* @deprecated Use {@link #setDefaultOption(String, Object)} instead.
- *
- * @param name the name of the option
+ * @param name the name of the option
* @param object the option
*/
@Deprecated
@@ -149,39 +132,45 @@
private final ReentrantLock m_mutex = new ReentrantLock();
@Override
- public void initSendable(SendableBuilder builder) {
+ public void initSendable(NTSendableBuilder builder) {
builder.setSmartDashboardType("String Chooser");
builder.getEntry(INSTANCE).setDouble(m_instance);
builder.addStringProperty(DEFAULT, () -> m_defaultChoice, null);
builder.addStringArrayProperty(OPTIONS, () -> m_map.keySet().toArray(new String[0]), null);
- builder.addStringProperty(ACTIVE, () -> {
- m_mutex.lock();
- try {
- if (m_selected != null) {
- return m_selected;
- } else {
- return m_defaultChoice;
- }
- } finally {
- m_mutex.unlock();
- }
- }, null);
+ builder.addStringProperty(
+ ACTIVE,
+ () -> {
+ m_mutex.lock();
+ try {
+ if (m_selected != null) {
+ return m_selected;
+ } else {
+ return m_defaultChoice;
+ }
+ } finally {
+ m_mutex.unlock();
+ }
+ },
+ null);
m_mutex.lock();
try {
m_activeEntries.add(builder.getEntry(ACTIVE));
} finally {
m_mutex.unlock();
}
- builder.addStringProperty(SELECTED, null, val -> {
- m_mutex.lock();
- try {
- m_selected = val;
- for (NetworkTableEntry entry : m_activeEntries) {
- entry.setString(val);
- }
- } finally {
- m_mutex.unlock();
- }
- });
+ builder.addStringProperty(
+ SELECTED,
+ null,
+ val -> {
+ m_mutex.lock();
+ try {
+ m_selected = val;
+ for (NetworkTableEntry entry : m_activeEntries) {
+ entry.setString(val);
+ }
+ } finally {
+ m_mutex.unlock();
+ }
+ });
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableRegistry.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableRegistry.java
deleted file mode 100644
index 3cafbf7..0000000
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableRegistry.java
+++ /dev/null
@@ -1,520 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.smartdashboard;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.function.Consumer;
-
-import edu.wpi.first.networktables.NetworkTable;
-import edu.wpi.first.wpilibj.DriverStation;
-import edu.wpi.first.wpilibj.Sendable;
-
-
-/**
- * The SendableRegistry class is the public interface for registering sensors
- * and actuators for use on dashboards and LiveWindow.
- */
-public class SendableRegistry {
- private static class Component {
- Component() {}
-
- Component(Sendable sendable) {
- m_sendable = new WeakReference<>(sendable);
- }
-
- WeakReference<Sendable> m_sendable;
- SendableBuilderImpl m_builder = new SendableBuilderImpl();
- String m_name;
- String m_subsystem = "Ungrouped";
- WeakReference<Sendable> m_parent;
- boolean m_liveWindow;
- Object[] m_data;
-
- void setName(String moduleType, int channel) {
- m_name = moduleType + "[" + channel + "]";
- }
-
- void setName(String moduleType, int moduleNumber, int channel) {
- m_name = moduleType + "[" + moduleNumber + "," + channel + "]";
- }
- }
-
- private static final Map<Object, Component> components = new WeakHashMap<>();
- private static int nextDataHandle;
-
- private static Component getOrAdd(Sendable sendable) {
- Component comp = components.get(sendable);
- if (comp == null) {
- comp = new Component(sendable);
- components.put(sendable, comp);
- } else {
- if (comp.m_sendable == null) {
- comp.m_sendable = new WeakReference<>(sendable);
- }
- }
- return comp;
- }
-
- private SendableRegistry() {
- throw new UnsupportedOperationException("This is a utility class!");
- }
-
- /**
- * Adds an object to the registry.
- *
- * @param sendable object to add
- * @param name component name
- */
- public static synchronized void add(Sendable sendable, String name) {
- Component comp = getOrAdd(sendable);
- comp.m_name = name;
- }
-
- /**
- * Adds an object to the registry.
- *
- * @param sendable object to add
- * @param moduleType A string that defines the module name in the label for
- * the value
- * @param channel The channel number the device is plugged into
- */
- public static synchronized void add(Sendable sendable, String moduleType, int channel) {
- Component comp = getOrAdd(sendable);
- comp.setName(moduleType, channel);
- }
-
- /**
- * Adds an object to the registry.
- *
- * @param sendable object to add
- * @param moduleType A string that defines the module name in the label for
- * the value
- * @param moduleNumber The number of the particular module type
- * @param channel The channel number the device is plugged into
- */
- public static synchronized void add(Sendable sendable, String moduleType, int moduleNumber,
- int channel) {
- Component comp = getOrAdd(sendable);
- comp.setName(moduleType, moduleNumber, channel);
- }
-
- /**
- * Adds an object to the registry.
- *
- * @param sendable object to add
- * @param subsystem subsystem name
- * @param name component name
- */
- public static synchronized void add(Sendable sendable, String subsystem, String name) {
- Component comp = getOrAdd(sendable);
- comp.m_name = name;
- comp.m_subsystem = subsystem;
- }
-
- /**
- * Adds an object to the registry and LiveWindow.
- *
- * @param sendable object to add
- * @param name component name
- */
- public static synchronized void addLW(Sendable sendable, String name) {
- Component comp = getOrAdd(sendable);
- comp.m_liveWindow = true;
- comp.m_name = name;
- }
-
- /**
- * Adds an object to the registry and LiveWindow.
- *
- * @param sendable object to add
- * @param moduleType A string that defines the module name in the label for
- * the value
- * @param channel The channel number the device is plugged into
- */
- public static synchronized void addLW(Sendable sendable, String moduleType, int channel) {
- Component comp = getOrAdd(sendable);
- comp.m_liveWindow = true;
- comp.setName(moduleType, channel);
- }
-
- /**
- * Adds an object to the registry and LiveWindow.
- *
- * @param sendable object to add
- * @param moduleType A string that defines the module name in the label for
- * the value
- * @param moduleNumber The number of the particular module type
- * @param channel The channel number the device is plugged into
- */
- public static synchronized void addLW(Sendable sendable, String moduleType, int moduleNumber,
- int channel) {
- Component comp = getOrAdd(sendable);
- comp.m_liveWindow = true;
- comp.setName(moduleType, moduleNumber, channel);
- }
-
- /**
- * Adds an object to the registry and LiveWindow.
- *
- * @param sendable object to add
- * @param subsystem subsystem name
- * @param name component name
- */
- public static synchronized void addLW(Sendable sendable, String subsystem, String name) {
- Component comp = getOrAdd(sendable);
- comp.m_liveWindow = true;
- comp.m_name = name;
- comp.m_subsystem = subsystem;
- }
-
- /**
- * Adds a child object to an object. Adds the child object to the registry
- * if it's not already present.
- *
- * @param parent parent object
- * @param child child object
- */
- public static synchronized void addChild(Sendable parent, Object child) {
- Component comp = components.get(child);
- if (comp == null) {
- comp = new Component();
- components.put(child, comp);
- }
- comp.m_parent = new WeakReference<>(parent);
- }
-
- /**
- * Removes an object from the registry.
- *
- * @param sendable object to remove
- * @return true if the object was removed; false if it was not present
- */
- public static synchronized boolean remove(Sendable sendable) {
- return components.remove(sendable) != null;
- }
-
- /**
- * Determines if an object is in the registry.
- *
- * @param sendable object to check
- * @return True if in registry, false if not.
- */
- public static synchronized boolean contains(Sendable sendable) {
- return components.containsKey(sendable);
- }
-
- /**
- * Gets the name of an object.
- *
- * @param sendable object
- * @return Name (empty if object is not in registry)
- */
- public static synchronized String getName(Sendable sendable) {
- Component comp = components.get(sendable);
- if (comp == null) {
- return "";
- }
- return comp.m_name;
- }
-
- /**
- * Sets the name of an object.
- *
- * @param sendable object
- * @param name name
- */
- public static synchronized void setName(Sendable sendable, String name) {
- Component comp = components.get(sendable);
- if (comp != null) {
- comp.m_name = name;
- }
- }
-
- /**
- * Sets the name of an object with a channel number.
- *
- * @param sendable object
- * @param moduleType A string that defines the module name in the label for
- * the value
- * @param channel The channel number the device is plugged into
- */
- public static synchronized void setName(Sendable sendable, String moduleType, int channel) {
- Component comp = components.get(sendable);
- if (comp != null) {
- comp.setName(moduleType, channel);
- }
- }
-
- /**
- * Sets the name of an object with a module and channel number.
- *
- * @param sendable object
- * @param moduleType A string that defines the module name in the label for
- * the value
- * @param moduleNumber The number of the particular module type
- * @param channel The channel number the device is plugged into
- */
- public static synchronized void setName(Sendable sendable, String moduleType, int moduleNumber,
- int channel) {
- Component comp = components.get(sendable);
- if (comp != null) {
- comp.setName(moduleType, moduleNumber, channel);
- }
- }
-
- /**
- * Sets both the subsystem name and device name of an object.
- *
- * @param sendable object
- * @param subsystem subsystem name
- * @param name device name
- */
- public static synchronized void setName(Sendable sendable, String subsystem, String name) {
- Component comp = components.get(sendable);
- if (comp != null) {
- comp.m_name = name;
- comp.m_subsystem = subsystem;
- }
- }
-
- /**
- * Gets the subsystem name of an object.
- *
- * @param sendable object
- * @return Subsystem name (empty if object is not in registry)
- */
- public static synchronized String getSubsystem(Sendable sendable) {
- Component comp = components.get(sendable);
- if (comp == null) {
- return "";
- }
- return comp.m_subsystem;
- }
-
- /**
- * Sets the subsystem name of an object.
- *
- * @param sendable object
- * @param subsystem subsystem name
- */
- public static synchronized void setSubsystem(Sendable sendable, String subsystem) {
- Component comp = components.get(sendable);
- if (comp != null) {
- comp.m_subsystem = subsystem;
- }
- }
-
- /**
- * Gets a unique handle for setting/getting data with setData() and getData().
- *
- * @return Handle
- */
- public static synchronized int getDataHandle() {
- return nextDataHandle++;
- }
-
- /**
- * Associates arbitrary data with an object in the registry.
- *
- * @param sendable object
- * @param handle data handle returned by getDataHandle()
- * @param data data to set
- * @return Previous data (may be null)
- */
- public static synchronized Object setData(Sendable sendable, int handle, Object data) {
- Component comp = components.get(sendable);
- if (comp == null) {
- return null;
- }
- Object rv = null;
- if (comp.m_data == null) {
- comp.m_data = new Object[handle + 1];
- } else if (handle < comp.m_data.length) {
- rv = comp.m_data[handle];
- } else {
- comp.m_data = Arrays.copyOf(comp.m_data, handle + 1);
- }
- comp.m_data[handle] = data;
- return rv;
- }
-
- /**
- * Gets arbitrary data associated with an object in the registry.
- *
- * @param sendable object
- * @param handle data handle returned by getDataHandle()
- * @return data (may be null if none associated)
- */
- public static synchronized Object getData(Sendable sendable, int handle) {
- Component comp = components.get(sendable);
- if (comp == null || comp.m_data == null || handle >= comp.m_data.length) {
- return null;
- }
- return comp.m_data[handle];
- }
-
- /**
- * Enables LiveWindow for an object.
- *
- * @param sendable object
- */
- public static synchronized void enableLiveWindow(Sendable sendable) {
- Component comp = components.get(sendable);
- if (comp != null) {
- comp.m_liveWindow = true;
- }
- }
-
- /**
- * Disables LiveWindow for an object.
- *
- * @param sendable object
- */
- public static synchronized void disableLiveWindow(Sendable sendable) {
- Component comp = components.get(sendable);
- if (comp != null) {
- comp.m_liveWindow = false;
- }
- }
-
- /**
- * Publishes an object in the registry to a network table.
- *
- * @param sendable object
- * @param table network table
- */
- public static synchronized void publish(Sendable sendable, NetworkTable table) {
- Component comp = getOrAdd(sendable);
- comp.m_builder.clearProperties();
- comp.m_builder.setTable(table);
- sendable.initSendable(comp.m_builder);
- comp.m_builder.updateTable();
- comp.m_builder.startListeners();
- }
-
- /**
- * Updates network table information from an object.
- *
- * @param sendable object
- */
- public static synchronized void update(Sendable sendable) {
- Component comp = components.get(sendable);
- if (comp != null) {
- comp.m_builder.updateTable();
- }
- }
-
- /**
- * Data passed to foreachLiveWindow() callback function.
- */
- public static class CallbackData {
- /**
- * Sendable object.
- */
- @SuppressWarnings("MemberName")
- public Sendable sendable;
-
- /**
- * Name.
- */
- @SuppressWarnings("MemberName")
- public String name;
-
- /**
- * Subsystem.
- */
- @SuppressWarnings("MemberName")
- public String subsystem;
-
- /**
- * Parent sendable object.
- */
- @SuppressWarnings("MemberName")
- public Sendable parent;
-
- /**
- * Data stored in object with setData(). Update this to change the data.
- */
- @SuppressWarnings("MemberName")
- public Object data;
-
- /**
- * Sendable builder for the sendable.
- */
- @SuppressWarnings("MemberName")
- public SendableBuilderImpl builder;
- }
-
- // As foreachLiveWindow is single threaded, cache the components it
- // iterates over to avoid risk of ConcurrentModificationException
- private static List<Component> foreachComponents = new ArrayList<>();
-
- /**
- * Iterates over LiveWindow-enabled objects in the registry.
- * It is *not* safe to call other SendableRegistry functions from the
- * callback.
- *
- * @param dataHandle data handle to get data object passed to callback
- * @param callback function to call for each object
- */
- @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.AvoidInstantiatingObjectsInLoops",
- "PMD.AvoidCatchingThrowable"})
- public static synchronized void foreachLiveWindow(int dataHandle,
- Consumer<CallbackData> callback) {
- CallbackData cbdata = new CallbackData();
- foreachComponents.clear();
- foreachComponents.addAll(components.values());
- for (Component comp : foreachComponents) {
- if (comp.m_sendable == null) {
- continue;
- }
- cbdata.sendable = comp.m_sendable.get();
- if (cbdata.sendable != null && comp.m_liveWindow) {
- cbdata.name = comp.m_name;
- cbdata.subsystem = comp.m_subsystem;
- if (comp.m_parent != null) {
- cbdata.parent = comp.m_parent.get();
- } else {
- cbdata.parent = null;
- }
- if (comp.m_data != null && dataHandle < comp.m_data.length) {
- cbdata.data = comp.m_data[dataHandle];
- } else {
- cbdata.data = null;
- }
- cbdata.builder = comp.m_builder;
- try {
- callback.accept(cbdata);
- } catch (Throwable throwable) {
- Throwable cause = throwable.getCause();
- if (cause != null) {
- throwable = cause;
- }
- DriverStation.reportError(
- "Unhandled exception calling LiveWindow for " + comp.m_name + ": "
- + throwable.toString(), false);
- comp.m_liveWindow = false;
- }
- if (cbdata.data != null) {
- if (comp.m_data == null) {
- comp.m_data = new Object[dataHandle + 1];
- } else if (dataHandle >= comp.m_data.length) {
- comp.m_data = Arrays.copyOf(comp.m_data, dataHandle + 1);
- }
- comp.m_data[dataHandle] = cbdata.data;
- }
- }
- }
- foreachComponents.clear();
- }
-}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboard.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboard.java
index 1b022c1..be5684b 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboard.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboard.java
@@ -1,23 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.smartdashboard;
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
import edu.wpi.first.hal.FRCNetComm.tResourceType;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
-import edu.wpi.first.wpilibj.Sendable;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableRegistry;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
/**
* The {@link SmartDashboard} class is the bridge between robot programs and the SmartDashboard on
@@ -26,24 +23,18 @@
* <p>When a value is put into the SmartDashboard here, it pops up on the SmartDashboard on the
* laptop. Users can put values into and get values from the SmartDashboard.
*/
-@SuppressWarnings("PMD.GodClass")
public final class SmartDashboard {
- /**
- * The {@link NetworkTable} used by {@link SmartDashboard}.
- */
+ /** The {@link NetworkTable} used by {@link SmartDashboard}. */
private static final NetworkTable table =
NetworkTableInstance.getDefault().getTable("SmartDashboard");
/**
- * A table linking tables in the SmartDashboard to the {@link Sendable} objects they
- * came from.
+ * A table linking tables in the SmartDashboard to the {@link Sendable} objects they came from.
*/
@SuppressWarnings("PMD.UseConcurrentHashMap")
private static final Map<String, Sendable> tablesToData = new HashMap<>();
- /**
- * The executor for listener tasks; calls listener tasks synchronously from main thread.
- */
+ /** The executor for listener tasks; calls listener tasks synchronously from main thread. */
private static final ListenerExecutor listenerExecutor = new ListenerExecutor();
static {
@@ -58,7 +49,7 @@
* Maps the specified key to the specified value in this table. The key can not be null. The value
* can be retrieved by calling the get method with a key that is equal to the original key.
*
- * @param key the key
+ * @param key the key
* @param data the value
* @throws IllegalArgumentException If key is null
*/
@@ -68,15 +59,18 @@
if (sddata == null || sddata != data) {
tablesToData.put(key, data);
NetworkTable dataTable = table.getSubTable(key);
- SendableRegistry.publish(data, dataTable);
+ SendableBuilderImpl builder = new SendableBuilderImpl();
+ builder.setTable(dataTable);
+ SendableRegistry.publish(data, builder);
+ builder.startListeners();
dataTable.getEntry(".name").setString(key);
}
}
/**
- * Maps the specified key (where the key is the name of the {@link Sendable}
- * to the specified value in this table. The value can be retrieved by
- * calling the get method with a key that is equal to the original key.
+ * Maps the specified key (where the key is the name of the {@link Sendable} to the specified
+ * value in this table. The value can be retrieved by calling the get method with a key that is
+ * equal to the original key.
*
* @param value the value
* @throws IllegalArgumentException If key is null
@@ -93,7 +87,7 @@
*
* @param key the key
* @return the value
- * @throws IllegalArgumentException if the key is null
+ * @throws IllegalArgumentException if the key is null
*/
public static synchronized Sendable getData(String key) {
Sendable data = tablesToData.get(key);
@@ -106,6 +100,7 @@
/**
* Gets the entry for the specified key.
+ *
* @param key the key name
* @return Network table entry.
*/
@@ -143,8 +138,7 @@
}
/**
- * Makes a key's value persistent through program restarts.
- * The key cannot be null.
+ * Makes a key's value persistent through program restarts. The key cannot be null.
*
* @param key the key name
*/
@@ -153,8 +147,7 @@
}
/**
- * Stop making a key's value persistent through program restarts.
- * The key cannot be null.
+ * Stop making a key's value persistent through program restarts. The key cannot be null.
*
* @param key the key name
*/
@@ -163,8 +156,7 @@
}
/**
- * Returns whether the value is persistent through program restarts.
- * The key cannot be null.
+ * Returns whether the value is persistent through program restarts. The key cannot be null.
*
* @param key the key name
* @return True if the value is persistent.
@@ -174,8 +166,7 @@
}
/**
- * Sets flags on the specified key in this table. The key can
- * not be null.
+ * Sets flags on the specified key in this table. The key can not be null.
*
* @param key the key name
* @param flags the flags to set (bitmask)
@@ -185,8 +176,7 @@
}
/**
- * Clears flags on the specified key in this table. The key can
- * not be null.
+ * Clears flags on the specified key in this table. The key can not be null.
*
* @param key the key name
* @param flags the flags to clear (bitmask)
@@ -206,8 +196,7 @@
}
/**
- * Deletes the specified key in this table. The key can
- * not be null.
+ * Deletes the specified key in this table. The key can not be null.
*
* @param key the key name
*/
@@ -217,6 +206,7 @@
/**
* Put a boolean in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -227,6 +217,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -236,12 +227,13 @@
}
/**
- * Returns the boolean the key maps to. If the key does not exist or is of
- * different type, it will return the default value.
+ * Returns the boolean the key maps to. If the key does not exist or is of different type, it will
+ * return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static boolean getBoolean(String key, boolean defaultValue) {
return getEntry(key).getBoolean(defaultValue);
@@ -249,6 +241,7 @@
/**
* Put a number in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -259,6 +252,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -268,12 +262,13 @@
}
/**
- * Returns the number the key maps to. If the key does not exist or is of
- * different type, it will return the default value.
+ * Returns the number the key maps to. If the key does not exist or is of different type, it will
+ * return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static double getNumber(String key, double defaultValue) {
return getEntry(key).getDouble(defaultValue);
@@ -281,6 +276,7 @@
/**
* Put a string in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -291,6 +287,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -300,12 +297,13 @@
}
/**
- * Returns the string the key maps to. If the key does not exist or is of
- * different type, it will return the default value.
+ * Returns the string the key maps to. If the key does not exist or is of different type, it will
+ * return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static String getString(String key, String defaultValue) {
return getEntry(key).getString(defaultValue);
@@ -313,6 +311,7 @@
/**
* Put a boolean array in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -323,6 +322,7 @@
/**
* Put a boolean array in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -333,6 +333,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -343,6 +344,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -352,24 +354,26 @@
}
/**
- * Returns the boolean array the key maps to. If the key does not exist or is
- * of different type, it will return the default value.
+ * Returns the boolean array the key maps to. If the key does not exist or is of different type,
+ * it will return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static boolean[] getBooleanArray(String key, boolean[] defaultValue) {
return getEntry(key).getBooleanArray(defaultValue);
}
/**
- * Returns the boolean array the key maps to. If the key does not exist or is
- * of different type, it will return the default value.
+ * Returns the boolean array the key maps to. If the key does not exist or is of different type,
+ * it will return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static Boolean[] getBooleanArray(String key, Boolean[] defaultValue) {
return getEntry(key).getBooleanArray(defaultValue);
@@ -377,6 +381,7 @@
/**
* Put a number array in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -387,6 +392,7 @@
/**
* Put a number array in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -397,6 +403,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -407,6 +414,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -416,24 +424,26 @@
}
/**
- * Returns the number array the key maps to. If the key does not exist or is
- * of different type, it will return the default value.
+ * Returns the number array the key maps to. If the key does not exist or is of different type, it
+ * will return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static double[] getNumberArray(String key, double[] defaultValue) {
return getEntry(key).getDoubleArray(defaultValue);
}
/**
- * Returns the number array the key maps to. If the key does not exist or is
- * of different type, it will return the default value.
+ * Returns the number array the key maps to. If the key does not exist or is of different type, it
+ * will return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static Double[] getNumberArray(String key, Double[] defaultValue) {
return getEntry(key).getDoubleArray(defaultValue);
@@ -441,6 +451,7 @@
/**
* Put a string array in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -451,6 +462,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -460,12 +472,13 @@
}
/**
- * Returns the string array the key maps to. If the key does not exist or is
- * of different type, it will return the default value.
+ * Returns the string array the key maps to. If the key does not exist or is of different type, it
+ * will return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static String[] getStringArray(String key, String[] defaultValue) {
return getEntry(key).getStringArray(defaultValue);
@@ -473,6 +486,7 @@
/**
* Put a raw value (byte array) in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
@@ -483,6 +497,7 @@
/**
* Put a raw value (bytes from a byte buffer) in the table.
+ *
* @param key the key to be assigned to
* @param value the value that will be assigned
* @param len the length of the value
@@ -494,6 +509,7 @@
/**
* Gets the current value in the table, setting it if it does not exist.
+ *
* @param key the key
* @param defaultValue the default value to set if key does not exist.
* @return False if the table key exists with a different type
@@ -503,20 +519,21 @@
}
/**
- * Returns the raw value (byte array) the key maps to. If the key does not
- * exist or is of different type, it will return the default value.
+ * Returns the raw value (byte array) the key maps to. If the key does not exist or is of
+ * different type, it will return the default value.
+ *
* @param key the key to look up
* @param defaultValue the value to be returned if no value is found
- * @return the value associated with the given key or the given default value
- * if there is no value associated with the key
+ * @return the value associated with the given key or the given default value if there is no value
+ * associated with the key
*/
public static byte[] getRaw(String key, byte[] defaultValue) {
return getEntry(key).getRaw(defaultValue);
}
/**
- * Posts a task from a listener to the ListenerExecutor, so that it can be run synchronously
- * from the main loop on the next call to {@link SmartDashboard#updateValues()}.
+ * Posts a task from a listener to the ListenerExecutor, so that it can be run synchronously from
+ * the main loop on the next call to {@link SmartDashboard#updateValues()}.
*
* @param task The task to run synchronously from the main thread.
*/
@@ -524,14 +541,12 @@
listenerExecutor.execute(task);
}
- /**
- * Puts all sendable data to the dashboard.
- */
+ /** Puts all sendable data to the dashboard. */
public static synchronized void updateValues() {
+ // Execute posted listener tasks
+ listenerExecutor.runListenerTasks();
for (Sendable data : tablesToData.values()) {
SendableRegistry.update(data);
}
- // Execute posted listener tasks
- listenerExecutor.runListenerTasks();
}
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java
index a576991..1287f4a 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java
@@ -1,16 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.util;
+import edu.wpi.first.math.MathUtil;
import java.util.Objects;
-import edu.wpi.first.wpiutil.math.MathUtil;
-
/**
* Represents colors.
*
@@ -27,9 +23,9 @@
/**
* Constructs a Color.
*
- * @param red Red value (0-1)
+ * @param red Red value (0-1)
* @param green Green value (0-1)
- * @param blue Blue value (0-1)
+ * @param blue Blue value (0-1)
*/
public Color(double red, double green, double blue) {
this.red = roundAndClamp(red);
@@ -43,9 +39,7 @@
* @param color The color
*/
public Color(Color8Bit color) {
- this(color.red / 255.0,
- color.green / 255.0,
- color.blue / 255.0);
+ this(color.red / 255.0, color.green / 255.0, color.blue / 255.0);
}
/**
@@ -114,722 +108,436 @@
* FIRST Colors
*/
- /**
- * #1560BD.
- */
+ /** 0x1560BD. */
public static final Color kDenim = new Color(0.0823529412, 0.376470589, 0.7411764706);
- /**
- * #0066B3.
- */
+ /** 0x0066B3. */
public static final Color kFirstBlue = new Color(0.0, 0.4, 0.7019607844);
- /**
- * #ED1C24.
- */
+ /** 0xED1C24. */
public static final Color kFirstRed = new Color(0.9294117648, 0.1098039216, 0.1411764706);
/*
* Standard Colors
*/
- /**
- * #F0F8FF.
- */
+ /** 0xF0F8FF. */
public static final Color kAliceBlue = new Color(0.9411765f, 0.972549f, 1.0f);
- /**
- * #FAEBD7.
- */
+ /** 0xFAEBD7. */
public static final Color kAntiqueWhite = new Color(0.98039216f, 0.92156863f, 0.84313726f);
- /**
- * #00FFFF.
- */
+ /** 0x00FFFF. */
public static final Color kAqua = new Color(0.0f, 1.0f, 1.0f);
- /**
- * #7FFFD4.
- */
+ /** 0x7FFFD4. */
public static final Color kAquamarine = new Color(0.49803922f, 1.0f, 0.83137256f);
- /**
- * #F0FFFF.
- */
+ /** 0xF0FFFF. */
public static final Color kAzure = new Color(0.9411765f, 1.0f, 1.0f);
- /**
- * #F5F5DC.
- */
+ /** 0xF5F5DC. */
public static final Color kBeige = new Color(0.9607843f, 0.9607843f, 0.8627451f);
- /**
- * #FFE4C4.
- */
+ /** 0xFFE4C4. */
public static final Color kBisque = new Color(1.0f, 0.89411765f, 0.76862746f);
- /**
- * #000000.
- */
+ /** 0x000000. */
public static final Color kBlack = new Color(0.0f, 0.0f, 0.0f);
- /**
- * #FFEBCD.
- */
+ /** 0xFFEBCD. */
public static final Color kBlanchedAlmond = new Color(1.0f, 0.92156863f, 0.8039216f);
- /**
- * #0000FF.
- */
+ /** 0x0000FF. */
public static final Color kBlue = new Color(0.0f, 0.0f, 1.0f);
- /**
- * #8A2BE2.
- */
+ /** 0x8A2BE2. */
public static final Color kBlueViolet = new Color(0.5411765f, 0.16862746f, 0.8862745f);
- /**
- * #A52A2A.
- */
+ /** 0xA52A2A. */
public static final Color kBrown = new Color(0.64705884f, 0.16470589f, 0.16470589f);
- /**
- * #DEB887.
- */
+ /** 0xDEB887. */
public static final Color kBurlywood = new Color(0.87058824f, 0.72156864f, 0.5294118f);
- /**
- * #5F9EA0.
- */
+ /** 0x5F9EA0. */
public static final Color kCadetBlue = new Color(0.37254903f, 0.61960787f, 0.627451f);
- /**
- * #7FFF00.
- */
+ /** 0x7FFF00. */
public static final Color kChartreuse = new Color(0.49803922f, 1.0f, 0.0f);
- /**
- * #D2691E.
- */
+ /** 0xD2691E. */
public static final Color kChocolate = new Color(0.8235294f, 0.4117647f, 0.11764706f);
- /**
- * #FF7F50.
- */
+ /** 0xFF7F50. */
public static final Color kCoral = new Color(1.0f, 0.49803922f, 0.3137255f);
- /**
- * #6495ED.
- */
+ /** 0x6495ED. */
public static final Color kCornflowerBlue = new Color(0.39215687f, 0.58431375f, 0.92941177f);
- /**
- * #FFF8DC.
- */
+ /** 0xFFF8DC. */
public static final Color kCornsilk = new Color(1.0f, 0.972549f, 0.8627451f);
- /**
- * #DC143C.
- */
+ /** 0xDC143C. */
public static final Color kCrimson = new Color(0.8627451f, 0.078431375f, 0.23529412f);
- /**
- * #00FFFF.
- */
+ /** 0x00FFFF. */
public static final Color kCyan = new Color(0.0f, 1.0f, 1.0f);
- /**
- * #00008B.
- */
+ /** 0x00008B. */
public static final Color kDarkBlue = new Color(0.0f, 0.0f, 0.54509807f);
- /**
- * #008B8B.
- */
+ /** 0x008B8B. */
public static final Color kDarkCyan = new Color(0.0f, 0.54509807f, 0.54509807f);
- /**
- * #B8860B.
- */
+ /** 0xB8860B. */
public static final Color kDarkGoldenrod = new Color(0.72156864f, 0.5254902f, 0.043137256f);
- /**
- * #A9A9A9.
- */
+ /** 0xA9A9A9. */
public static final Color kDarkGray = new Color(0.6627451f, 0.6627451f, 0.6627451f);
- /**
- * #006400.
- */
+ /** 0x006400. */
public static final Color kDarkGreen = new Color(0.0f, 0.39215687f, 0.0f);
- /**
- * #BDB76B.
- */
+ /** 0xBDB76B. */
public static final Color kDarkKhaki = new Color(0.7411765f, 0.7176471f, 0.41960785f);
- /**
- * #8B008B.
- */
+ /** 0x8B008B. */
public static final Color kDarkMagenta = new Color(0.54509807f, 0.0f, 0.54509807f);
- /**
- * #556B2F.
- */
+ /** 0x556B2F. */
public static final Color kDarkOliveGreen = new Color(0.33333334f, 0.41960785f, 0.18431373f);
- /**
- * #FF8C00.
- */
+ /** 0xFF8C00. */
public static final Color kDarkOrange = new Color(1.0f, 0.54901963f, 0.0f);
- /**
- * #9932CC.
- */
+ /** 0x9932CC. */
public static final Color kDarkOrchid = new Color(0.6f, 0.19607843f, 0.8f);
- /**
- * #8B0000.
- */
+ /** 0x8B0000. */
public static final Color kDarkRed = new Color(0.54509807f, 0.0f, 0.0f);
- /**
- * #E9967A.
- */
+ /** 0xE9967A. */
public static final Color kDarkSalmon = new Color(0.9137255f, 0.5882353f, 0.47843137f);
- /**
- * #8FBC8F.
- */
+ /** 0x8FBC8F. */
public static final Color kDarkSeaGreen = new Color(0.56078434f, 0.7372549f, 0.56078434f);
- /**
- * #483D8B.
- */
+ /** 0x483D8B. */
public static final Color kDarkSlateBlue = new Color(0.28235295f, 0.23921569f, 0.54509807f);
- /**
- * #2F4F4F.
- */
+ /** 0x2F4F4F. */
public static final Color kDarkSlateGray = new Color(0.18431373f, 0.30980393f, 0.30980393f);
- /**
- * #00CED1.
- */
+ /** 0x00CED1. */
public static final Color kDarkTurquoise = new Color(0.0f, 0.80784315f, 0.81960785f);
- /**
- * #9400D3.
- */
+ /** 0x9400D3. */
public static final Color kDarkViolet = new Color(0.5803922f, 0.0f, 0.827451f);
- /**
- * #FF1493.
- */
+ /** 0xFF1493. */
public static final Color kDeepPink = new Color(1.0f, 0.078431375f, 0.5764706f);
- /**
- * #00BFFF.
- */
+ /** 0x00BFFF. */
public static final Color kDeepSkyBlue = new Color(0.0f, 0.7490196f, 1.0f);
- /**
- * #696969.
- */
+ /** 0x696969. */
public static final Color kDimGray = new Color(0.4117647f, 0.4117647f, 0.4117647f);
- /**
- * #1E90FF.
- */
+ /** 0x1E90FF. */
public static final Color kDodgerBlue = new Color(0.11764706f, 0.5647059f, 1.0f);
- /**
- * #B22222.
- */
+ /** 0xB22222. */
public static final Color kFirebrick = new Color(0.69803923f, 0.13333334f, 0.13333334f);
- /**
- * #FFFAF0.
- */
+ /** 0xFFFAF0. */
public static final Color kFloralWhite = new Color(1.0f, 0.98039216f, 0.9411765f);
- /**
- * #228B22.
- */
+ /** 0x228B22. */
public static final Color kForestGreen = new Color(0.13333334f, 0.54509807f, 0.13333334f);
- /**
- * #FF00FF.
- */
+ /** 0xFF00FF. */
public static final Color kFuchsia = new Color(1.0f, 0.0f, 1.0f);
- /**
- * #DCDCDC.
- */
+ /** 0xDCDCDC. */
public static final Color kGainsboro = new Color(0.8627451f, 0.8627451f, 0.8627451f);
- /**
- * #F8F8FF.
- */
+ /** 0xF8F8FF. */
public static final Color kGhostWhite = new Color(0.972549f, 0.972549f, 1.0f);
- /**
- * #FFD700.
- */
+ /** 0xFFD700. */
public static final Color kGold = new Color(1.0f, 0.84313726f, 0.0f);
- /**
- * #DAA520.
- */
+ /** 0xDAA520. */
public static final Color kGoldenrod = new Color(0.85490197f, 0.64705884f, 0.1254902f);
- /**
- * #808080.
- */
+ /** 0x808080. */
public static final Color kGray = new Color(0.5019608f, 0.5019608f, 0.5019608f);
- /**
- * #008000.
- */
+ /** 0x008000. */
public static final Color kGreen = new Color(0.0f, 0.5019608f, 0.0f);
- /**
- * #ADFF2F.
- */
+ /** 0xADFF2F. */
public static final Color kGreenYellow = new Color(0.6784314f, 1.0f, 0.18431373f);
- /**
- * #F0FFF0.
- */
+ /** 0xF0FFF0. */
public static final Color kHoneydew = new Color(0.9411765f, 1.0f, 0.9411765f);
- /**
- * #FF69B4.
- */
+ /** 0xFF69B4. */
public static final Color kHotPink = new Color(1.0f, 0.4117647f, 0.7058824f);
- /**
- * #CD5C5C.
- */
+ /** 0xCD5C5C. */
public static final Color kIndianRed = new Color(0.8039216f, 0.36078432f, 0.36078432f);
- /**
- * #4B0082.
- */
+ /** 0x4B0082. */
public static final Color kIndigo = new Color(0.29411766f, 0.0f, 0.50980395f);
- /**
- * #FFFFF0.
- */
+ /** 0xFFFFF0. */
public static final Color kIvory = new Color(1.0f, 1.0f, 0.9411765f);
- /**
- * #F0E68C.
- */
+ /** 0xF0E68C. */
public static final Color kKhaki = new Color(0.9411765f, 0.9019608f, 0.54901963f);
- /**
- * #E6E6FA.
- */
+ /** 0xE6E6FA. */
public static final Color kLavender = new Color(0.9019608f, 0.9019608f, 0.98039216f);
- /**
- * #FFF0F5.
- */
+ /** 0xFFF0F5. */
public static final Color kLavenderBlush = new Color(1.0f, 0.9411765f, 0.9607843f);
- /**
- * #7CFC00.
- */
+ /** 0x7CFC00. */
public static final Color kLawnGreen = new Color(0.4862745f, 0.9882353f, 0.0f);
- /**
- * #FFFACD.
- */
+ /** 0xFFFACD. */
public static final Color kLemonChiffon = new Color(1.0f, 0.98039216f, 0.8039216f);
- /**
- * #ADD8E6.
- */
+ /** 0xADD8E6. */
public static final Color kLightBlue = new Color(0.6784314f, 0.84705883f, 0.9019608f);
- /**
- * #F08080.
- */
+ /** 0xF08080. */
public static final Color kLightCoral = new Color(0.9411765f, 0.5019608f, 0.5019608f);
- /**
- * #E0FFFF.
- */
+ /** 0xE0FFFF. */
public static final Color kLightCyan = new Color(0.8784314f, 1.0f, 1.0f);
- /**
- * #FAFAD2.
- */
+ /** 0xFAFAD2. */
public static final Color kLightGoldenrodYellow = new Color(0.98039216f, 0.98039216f, 0.8235294f);
- /**
- * #D3D3D3.
- */
+ /** 0xD3D3D3. */
public static final Color kLightGray = new Color(0.827451f, 0.827451f, 0.827451f);
- /**
- * #90EE90.
- */
+ /** 0x90EE90. */
public static final Color kLightGreen = new Color(0.5647059f, 0.93333334f, 0.5647059f);
- /**
- * #FFB6C1.
- */
+ /** 0xFFB6C1. */
public static final Color kLightPink = new Color(1.0f, 0.7137255f, 0.75686276f);
- /**
- * #FFA07A.
- */
+ /** 0xFFA07A. */
public static final Color kLightSalmon = new Color(1.0f, 0.627451f, 0.47843137f);
- /**
- * #20B2AA.
- */
+ /** 0x20B2AA. */
public static final Color kLightSeaGreen = new Color(0.1254902f, 0.69803923f, 0.6666667f);
- /**
- * #87CEFA.
- */
+ /** 0x87CEFA. */
public static final Color kLightSkyBlue = new Color(0.5294118f, 0.80784315f, 0.98039216f);
- /**
- * #778899.
- */
+ /** 0x778899. */
public static final Color kLightSlateGray = new Color(0.46666667f, 0.53333336f, 0.6f);
- /**
- * #B0C4DE.
- */
+ /** 0xB0C4DE. */
public static final Color kLightSteelBlue = new Color(0.6901961f, 0.76862746f, 0.87058824f);
- /**
- * #FFFFE0.
- */
+ /** 0xFFFFE0. */
public static final Color kLightYellow = new Color(1.0f, 1.0f, 0.8784314f);
- /**
- * #00FF00.
- */
+ /** 0x00FF00. */
public static final Color kLime = new Color(0.0f, 1.0f, 0.0f);
- /**
- * #32CD32.
- */
+ /** 0x32CD32. */
public static final Color kLimeGreen = new Color(0.19607843f, 0.8039216f, 0.19607843f);
- /**
- * #FAF0E6.
- */
+ /** 0xFAF0E6. */
public static final Color kLinen = new Color(0.98039216f, 0.9411765f, 0.9019608f);
- /**
- * #FF00FF.
- */
+ /** 0xFF00FF. */
public static final Color kMagenta = new Color(1.0f, 0.0f, 1.0f);
- /**
- * #800000.
- */
+ /** 0x800000. */
public static final Color kMaroon = new Color(0.5019608f, 0.0f, 0.0f);
- /**
- * #66CDAA.
- */
+ /** 0x66CDAA. */
public static final Color kMediumAquamarine = new Color(0.4f, 0.8039216f, 0.6666667f);
- /**
- * #0000CD.
- */
+ /** 0x0000CD. */
public static final Color kMediumBlue = new Color(0.0f, 0.0f, 0.8039216f);
- /**
- * #BA55D3.
- */
+ /** 0xBA55D3. */
public static final Color kMediumOrchid = new Color(0.7294118f, 0.33333334f, 0.827451f);
- /**
- * #9370DB.
- */
+ /** 0x9370DB. */
public static final Color kMediumPurple = new Color(0.5764706f, 0.4392157f, 0.85882354f);
- /**
- * #3CB371.
- */
+ /** 0x3CB371. */
public static final Color kMediumSeaGreen = new Color(0.23529412f, 0.7019608f, 0.44313726f);
- /**
- * #7B68EE.
- */
+ /** 0x7B68EE. */
public static final Color kMediumSlateBlue = new Color(0.48235294f, 0.40784314f, 0.93333334f);
- /**
- * #00FA9A.
- */
+ /** 0x00FA9A. */
public static final Color kMediumSpringGreen = new Color(0.0f, 0.98039216f, 0.6039216f);
- /**
- * #48D1CC.
- */
+ /** 0x48D1CC. */
public static final Color kMediumTurquoise = new Color(0.28235295f, 0.81960785f, 0.8f);
- /**
- * #C71585.
- */
+ /** 0xC71585. */
public static final Color kMediumVioletRed = new Color(0.78039217f, 0.08235294f, 0.52156866f);
- /**
- * #191970.
- */
+ /** 0x191970. */
public static final Color kMidnightBlue = new Color(0.09803922f, 0.09803922f, 0.4392157f);
- /**
- * #F5FFFA.
- */
+ /** 0xF5FFFA. */
public static final Color kMintcream = new Color(0.9607843f, 1.0f, 0.98039216f);
- /**
- * #FFE4E1.
- */
+ /** 0xFFE4E1. */
public static final Color kMistyRose = new Color(1.0f, 0.89411765f, 0.88235295f);
- /**
- * #FFE4B5.
- */
+ /** 0xFFE4B5. */
public static final Color kMoccasin = new Color(1.0f, 0.89411765f, 0.70980394f);
- /**
- * #FFDEAD.
- */
+ /** 0xFFDEAD. */
public static final Color kNavajoWhite = new Color(1.0f, 0.87058824f, 0.6784314f);
- /**
- * #000080.
- */
+ /** 0x000080. */
public static final Color kNavy = new Color(0.0f, 0.0f, 0.5019608f);
- /**
- * #FDF5E6.
- */
+ /** 0xFDF5E6. */
public static final Color kOldLace = new Color(0.99215686f, 0.9607843f, 0.9019608f);
- /**
- * #808000.
- */
+ /** 0x808000. */
public static final Color kOlive = new Color(0.5019608f, 0.5019608f, 0.0f);
- /**
- * #6B8E23.
- */
+ /** 0x6B8E23. */
public static final Color kOliveDrab = new Color(0.41960785f, 0.5568628f, 0.13725491f);
- /**
- * #FFA500.
- */
+ /** 0xFFA500. */
public static final Color kOrange = new Color(1.0f, 0.64705884f, 0.0f);
- /**
- * #FF4500.
- */
+ /** 0xFF4500. */
public static final Color kOrangeRed = new Color(1.0f, 0.27058825f, 0.0f);
- /**
- * #DA70D6.
- */
+ /** 0xDA70D6. */
public static final Color kOrchid = new Color(0.85490197f, 0.4392157f, 0.8392157f);
- /**
- * #EEE8AA.
- */
+ /** 0xEEE8AA. */
public static final Color kPaleGoldenrod = new Color(0.93333334f, 0.9098039f, 0.6666667f);
- /**
- * #98FB98.
- */
+ /** 0x98FB98. */
public static final Color kPaleGreen = new Color(0.59607846f, 0.9843137f, 0.59607846f);
- /**
- * #AFEEEE.
- */
+ /** 0xAFEEEE. */
public static final Color kPaleTurquoise = new Color(0.6862745f, 0.93333334f, 0.93333334f);
- /**
- * #DB7093.
- */
+ /** 0xDB7093. */
public static final Color kPaleVioletRed = new Color(0.85882354f, 0.4392157f, 0.5764706f);
- /**
- * #FFEFD5.
- */
+ /** 0xFFEFD5. */
public static final Color kPapayaWhip = new Color(1.0f, 0.9372549f, 0.8352941f);
- /**
- * #FFDAB9.
- */
+ /** 0xFFDAB9. */
public static final Color kPeachPuff = new Color(1.0f, 0.85490197f, 0.7254902f);
- /**
- * #CD853F.
- */
+ /** 0xCD853F. */
public static final Color kPeru = new Color(0.8039216f, 0.52156866f, 0.24705882f);
- /**
- * #FFC0CB.
- */
+ /** 0xFFC0CB. */
public static final Color kPink = new Color(1.0f, 0.7529412f, 0.79607844f);
- /**
- * #DDA0DD.
- */
+ /** 0xDDA0DD. */
public static final Color kPlum = new Color(0.8666667f, 0.627451f, 0.8666667f);
- /**
- * #B0E0E6.
- */
+ /** 0xB0E0E6. */
public static final Color kPowderBlue = new Color(0.6901961f, 0.8784314f, 0.9019608f);
- /**
- * #800080.
- */
+ /** 0x800080. */
public static final Color kPurple = new Color(0.5019608f, 0.0f, 0.5019608f);
- /**
- * #FF0000.
- */
+ /** 0xFF0000. */
public static final Color kRed = new Color(1.0f, 0.0f, 0.0f);
- /**
- * #BC8F8F.
- */
+ /** 0xBC8F8F. */
public static final Color kRosyBrown = new Color(0.7372549f, 0.56078434f, 0.56078434f);
- /**
- * #4169E1.
- */
+ /** 0x4169E1. */
public static final Color kRoyalBlue = new Color(0.25490198f, 0.4117647f, 0.88235295f);
- /**
- * #8B4513.
- */
+ /** 0x8B4513. */
public static final Color kSaddleBrown = new Color(0.54509807f, 0.27058825f, 0.07450981f);
- /**
- * #FA8072.
- */
+ /** 0xFA8072. */
public static final Color kSalmon = new Color(0.98039216f, 0.5019608f, 0.44705883f);
- /**
- * #F4A460.
- */
+ /** 0xF4A460. */
public static final Color kSandyBrown = new Color(0.95686275f, 0.6431373f, 0.3764706f);
- /**
- * #2E8B57.
- */
+ /** 0x2E8B57. */
public static final Color kSeaGreen = new Color(0.18039216f, 0.54509807f, 0.34117648f);
- /**
- * #FFF5EE.
- */
+ /** 0xFFF5EE. */
public static final Color kSeashell = new Color(1.0f, 0.9607843f, 0.93333334f);
- /**
- * #A0522D.
- */
+ /** 0xA0522D. */
public static final Color kSienna = new Color(0.627451f, 0.32156864f, 0.1764706f);
- /**
- * #C0C0C0.
- */
+ /** 0xC0C0C0. */
public static final Color kSilver = new Color(0.7529412f, 0.7529412f, 0.7529412f);
- /**
- * #87CEEB.
- */
+ /** 0x87CEEB. */
public static final Color kSkyBlue = new Color(0.5294118f, 0.80784315f, 0.92156863f);
- /**
- * #6A5ACD.
- */
+ /** 0x6A5ACD. */
public static final Color kSlateBlue = new Color(0.41568628f, 0.3529412f, 0.8039216f);
- /**
- * #708090.
- */
+ /** 0x708090. */
public static final Color kSlateGray = new Color(0.4392157f, 0.5019608f, 0.5647059f);
- /**
- * #FFFAFA.
- */
+ /** 0xFFFAFA. */
public static final Color kSnow = new Color(1.0f, 0.98039216f, 0.98039216f);
- /**
- * #00FF7F.
- */
+ /** 0x00FF7F. */
public static final Color kSpringGreen = new Color(0.0f, 1.0f, 0.49803922f);
- /**
- * #4682B4.
- */
+ /** 0x4682B4. */
public static final Color kSteelBlue = new Color(0.27450982f, 0.50980395f, 0.7058824f);
- /**
- * #D2B48C.
- */
+ /** 0xD2B48C. */
public static final Color kTan = new Color(0.8235294f, 0.7058824f, 0.54901963f);
- /**
- * #008080.
- */
+ /** 0x008080. */
public static final Color kTeal = new Color(0.0f, 0.5019608f, 0.5019608f);
- /**
- * #D8BFD8.
- */
+ /** 0xD8BFD8. */
public static final Color kThistle = new Color(0.84705883f, 0.7490196f, 0.84705883f);
- /**
- * #FF6347.
- */
+ /** 0xFF6347. */
public static final Color kTomato = new Color(1.0f, 0.3882353f, 0.2784314f);
- /**
- * #40E0D0.
- */
+ /** 0x40E0D0. */
public static final Color kTurquoise = new Color(0.2509804f, 0.8784314f, 0.8156863f);
- /**
- * #EE82EE.
- */
+ /** 0xEE82EE. */
public static final Color kViolet = new Color(0.93333334f, 0.50980395f, 0.93333334f);
- /**
- * #F5DEB3.
- */
+ /** 0xF5DEB3. */
public static final Color kWheat = new Color(0.9607843f, 0.87058824f, 0.7019608f);
- /**
- * #FFFFFF.
- */
+ /** 0xFFFFFF. */
public static final Color kWhite = new Color(1.0f, 1.0f, 1.0f);
- /**
- * #F5F5F5.
- */
+ /** 0xF5F5F5. */
public static final Color kWhiteSmoke = new Color(0.9607843f, 0.9607843f, 0.9607843f);
- /**
- * #FFFF00.
- */
+ /** 0xFFFF00. */
public static final Color kYellow = new Color(1.0f, 1.0f, 0.0f);
- /**
- * #9ACD32.
- */
+ /** 0x9ACD32. */
public static final Color kYellowGreen = new Color(0.6039216f, 0.8039216f, 0.19607843f);
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java
index 50d42fc..cd7154d 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color8Bit.java
@@ -1,19 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.util;
+import edu.wpi.first.math.MathUtil;
import java.util.Objects;
-import edu.wpi.first.wpiutil.math.MathUtil;
-
-/**
- * Represents colors with 8 bits of precision.
- */
+/** Represents colors with 8 bits of precision. */
@SuppressWarnings("MemberName")
public class Color8Bit {
public final int red;
@@ -23,9 +17,9 @@
/**
* Constructs a Color8Bit.
*
- * @param red Red value (0-255)
+ * @param red Red value (0-255)
* @param green Green value (0-255)
- * @param blue Blue value (0-255)
+ * @param blue Blue value (0-255)
*/
public Color8Bit(int red, int green, int blue) {
this.red = MathUtil.clamp(red, 0, 255);
@@ -39,9 +33,7 @@
* @param color The color
*/
public Color8Bit(Color color) {
- this((int) (color.red * 255),
- (int) (color.green * 255),
- (int) (color.blue * 255));
+ this((int) (color.red * 255), (int) (color.green * 255), (int) (color.blue * 255));
}
@Override
@@ -54,9 +46,7 @@
}
Color8Bit color8Bit = (Color8Bit) other;
- return red == color8Bit.red
- && green == color8Bit.green
- && blue == color8Bit.blue;
+ return red == color8Bit.red && green == color8Bit.green && blue == color8Bit.blue;
}
@Override
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/ErrorMessages.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/ErrorMessages.java
index 8bc86b2..c5b5832 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/ErrorMessages.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/ErrorMessages.java
@@ -1,36 +1,36 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.util;
import static java.util.Objects.requireNonNull;
-/**
- * Utility class for common WPILib error messages.
- */
+/** Utility class for common WPILib error messages. */
public final class ErrorMessages {
- /**
- * Utility class, so constructor is private.
- */
+ /** Utility class, so constructor is private. */
private ErrorMessages() {
throw new UnsupportedOperationException("This is a utility class!");
}
/**
- * Requires that a parameter of a method not be null; prints an error message with
- * helpful debugging instructions if the parameter is null.
+ * Requires that a parameter of a method not be null; prints an error message with helpful
+ * debugging instructions if the parameter is null.
*
+ * @param <T> Type of object.
* @param obj The parameter that must not be null.
* @param paramName The name of the parameter.
* @param methodName The name of the method.
+ * @return The object parameter confirmed not to be null.
*/
public static <T> T requireNonNullParam(T obj, String paramName, String methodName) {
- return requireNonNull(obj,
- "Parameter " + paramName + " in method " + methodName + " was null when it"
+ return requireNonNull(
+ obj,
+ "Parameter "
+ + paramName
+ + " in method "
+ + methodName
+ + " was null when it"
+ " should not have been! Check the stacktrace to find the responsible line of code - "
+ "usually, it is the first line of user-written code indicated in the stacktrace. "
+ "Make sure all objects passed to the method in question were properly initialized -"
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionPipeline.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionPipeline.java
index 2c0f8f2..d888d3b 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionPipeline.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionPipeline.java
@@ -1,29 +1,26 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.vision;
import org.opencv.core.Mat;
/**
- * A vision pipeline is responsible for running a group of
- * OpenCV algorithms to extract data from an image.
+ * A vision pipeline is responsible for running a group of OpenCV algorithms to extract data from an
+ * image.
*
* @see VisionRunner
* @see VisionThread
- *
* @deprecated Replaced with edu.wpi.first.vision.VisionPipeline
*/
@Deprecated
public interface VisionPipeline {
/**
- * Processes the image input and sets the result objects.
- * Implementations should make these objects accessible.
+ * Processes the image input and sets the result objects. Implementations should make these
+ * objects accessible.
+ *
+ * @param image The image to process.
*/
void process(Mat image);
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionRunner.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionRunner.java
index 328686a..a1002f5 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionRunner.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionRunner.java
@@ -1,27 +1,22 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.vision;
+import edu.wpi.first.cameraserver.CameraServerSharedStore;
+import edu.wpi.first.cscore.CvSink;
+import edu.wpi.first.cscore.VideoSource;
import org.opencv.core.Mat;
-import edu.wpi.cscore.CvSink;
-import edu.wpi.cscore.VideoSource;
-import edu.wpi.first.cameraserver.CameraServerSharedStore;
-
/**
- * A vision runner is a convenient wrapper object to make it easy to run vision pipelines
- * from robot code. The easiest way to use this is to run it in a {@link VisionThread}
- * and use the listener to take snapshots of the pipeline's outputs.
+ * A vision runner is a convenient wrapper object to make it easy to run vision pipelines from robot
+ * code. The easiest way to use this is to run it in a {@link VisionThread} and use the listener to
+ * take snapshots of the pipeline's outputs.
*
* @see VisionPipeline
* @see VisionThread
* @see <a href="package-summary.html">vision</a>
- *
* @deprecated Replaced with edu.wpi.first.vision.VisionRunner
*/
@Deprecated
@@ -48,17 +43,16 @@
* @param pipeline the vision pipeline that ran
*/
void copyPipelineOutputs(P pipeline);
-
}
/**
- * Creates a new vision runner. It will take images from the {@code videoSource}, send them to
- * the {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert
- * user code when it is safe to access the pipeline's outputs.
+ * Creates a new vision runner. It will take images from the {@code videoSource}, send them to the
+ * {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert user
+ * code when it is safe to access the pipeline's outputs.
*
* @param videoSource the video source to use to supply images for the pipeline
- * @param pipeline the vision pipeline to run
- * @param listener a function to call after the pipeline has finished running
+ * @param pipeline the vision pipeline to run
+ * @param listener a function to call after the pipeline has finished running
*/
public VisionRunner(VideoSource videoSource, P pipeline, Listener<? super P> listener) {
this.m_pipeline = pipeline;
@@ -67,15 +61,15 @@
}
/**
- * Runs the pipeline one time, giving it the next image from the video source specified
- * in the constructor. This will block until the source either has an image or throws an error.
- * If the source successfully supplied a frame, the pipeline's image input will be set,
- * the pipeline will run, and the listener specified in the constructor will be called to notify
- * it that the pipeline ran.
+ * Runs the pipeline one time, giving it the next image from the video source specified in the
+ * constructor. This will block until the source either has an image or throws an error. If the
+ * source successfully supplied a frame, the pipeline's image input will be set, the pipeline will
+ * run, and the listener specified in the constructor will be called to notify it that the
+ * pipeline ran.
*
- * <p>This method is exposed to allow teams to add additional functionality or have their own
- * ways to run the pipeline. Most teams, however, should just use {@link #runForever} in its own
- * thread using a {@link VisionThread}.</p>
+ * <p>This method is exposed to allow teams to add additional functionality or have their own ways
+ * to run the pipeline. Most teams, however, should just use {@link #runForever} in its own thread
+ * using a {@link VisionThread}.
*/
public void runOnce() {
Long id = CameraServerSharedStore.getCameraServerShared().getRobotMainThreadId();
@@ -101,11 +95,11 @@
}
/**
- * A convenience method that calls {@link #runOnce()} in an infinite loop. This must
- * be run in a dedicated thread, and cannot be used in the main robot thread because
- * it will freeze the robot program.
+ * A convenience method that calls {@link #runOnce()} in an infinite loop. This must be run in a
+ * dedicated thread, and cannot be used in the main robot thread because it will freeze the robot
+ * program.
*
- * <p><strong>Do not call this method directly from the main thread.</strong></p>
+ * <p><strong>Do not call this method directly from the main thread.</strong>
*
* @throws IllegalStateException if this is called from the main robot thread
* @see VisionThread
@@ -122,9 +116,7 @@
}
}
- /**
- * Stop a RunForever() loop.
- */
+ /** Stop a RunForever() loop. */
public void stop() {
m_enabled = false;
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionThread.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionThread.java
index 5184ba0..5f23fe1 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionThread.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/VisionThread.java
@@ -1,23 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.vision;
-import edu.wpi.cscore.VideoSource;
+import edu.wpi.first.cscore.VideoSource;
/**
- * A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread;
- * it does not prevent the program from exiting when all other non-daemon threads
- * have finished running.
+ * A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread; it
+ * does not prevent the program from exiting when all other non-daemon threads have finished
+ * running.
*
* @see VisionPipeline
* @see VisionRunner
* @see Thread#setDaemon(boolean)
- *
* @deprecated Replaced with edu.wpi.first.vision.VisionThread
*/
@Deprecated
@@ -37,14 +33,12 @@
* equivalent to {@code new VisionThread(new VisionRunner<>(videoSource, pipeline, listener))}.
*
* @param videoSource the source for images the pipeline should process
- * @param pipeline the pipeline to run
- * @param listener the listener to copy outputs from the pipeline after it runs
- * @param <P> the type of the pipeline
+ * @param pipeline the pipeline to run
+ * @param listener the listener to copy outputs from the pipeline after it runs
+ * @param <P> the type of the pipeline
*/
- public <P extends VisionPipeline> VisionThread(VideoSource videoSource,
- P pipeline,
- VisionRunner.Listener<? super P> listener) {
+ public <P extends VisionPipeline> VisionThread(
+ VideoSource videoSource, P pipeline, VisionRunner.Listener<? super P> listener) {
this(new VisionRunner<>(videoSource, pipeline, listener));
}
-
}
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/package-info.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/package-info.java
index 01c8d73..b52f4ed 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/package-info.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/vision/package-info.java
@@ -1,22 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// 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.
/**
- * Classes in the {@code edu.wpi.first.wpilibj.vision} package are designed to
- * simplify using OpenCV vision processing code from a robot program.
+ * Classes in the {@code edu.wpi.first.wpilibj.vision} package are designed to simplify using OpenCV
+ * vision processing code from a robot program.
*
- * <p>An example use case for grabbing a yellow tote from 2015 in autonomous:
- * <br>
+ * <p>An example use case for grabbing a yellow tote from 2015 in autonomous: <br>
+ *
* <pre><code>
* public class Robot extends IterativeRobot
* implements VisionRunner.Listener<MyFindTotePipeline> {
*
* // A USB camera connected to the roboRIO.
- * private {@link edu.wpi.cscore.VideoSource VideoSource} usbCamera;
+ * private {@link edu.wpi.first.cscore.VideoSource VideoSource} usbCamera;
*
* // A vision pipeline. This could be handwritten or generated by GRIP.
* // This has to implement {@link edu.wpi.first.wpilibj.vision.VisionPipeline}.
@@ -47,7 +44,7 @@
*
* {@literal @}Override
* public void robotInit() {
- * usbCamera = CameraServer.getInstance().startAutomaticCapture(0);
+ * usbCamera = CameraServer.startAutomaticCapture(0);
* findTotePipeline = new MyFindTotePipeline();
* findToteThread = new VisionThread(usbCamera, findTotePipeline, this);
* }
diff --git a/wpilibj/src/test/java/edu/wpi/first/math/util/ColorTest.java b/wpilibj/src/test/java/edu/wpi/first/math/util/ColorTest.java
new file mode 100644
index 0000000..6685314
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/math/util/ColorTest.java
@@ -0,0 +1,45 @@
+// 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.math.util;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+import edu.wpi.first.wpilibj.util.Color;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class ColorTest {
+ private static final double kEpsilon = 1e-3;
+
+ void assertColorMatches(double red, double green, double blue, Color color) {
+ assertAll(
+ () -> assertEquals(red, color.red, kEpsilon),
+ () -> assertEquals(green, color.green, kEpsilon),
+ () -> assertEquals(blue, color.blue, kEpsilon));
+ }
+
+ @ParameterizedTest
+ @MethodSource("staticColorProvider")
+ void staticColorTest(double red, double green, double blue, Color color) {
+ assertColorMatches(red, green, blue, color);
+ }
+
+ @ParameterizedTest
+ @MethodSource("staticColorProvider")
+ void colorEqualsTest(double red, double green, double blue, Color color) {
+ assertEquals(color, new Color(red, green, blue));
+ }
+
+ static Stream<Arguments> staticColorProvider() {
+ return Stream.of(
+ arguments(0.0823529412, 0.376470589, 0.7411764706, Color.kDenim),
+ arguments(0.0, 0.4, 0.7019607844, Color.kFirstBlue),
+ arguments(0.9294117648, 0.1098039216, 0.1411764706, Color.kFirstRed));
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/math/util/ErrorMessagesTest.java b/wpilibj/src/test/java/edu/wpi/first/math/util/ErrorMessagesTest.java
new file mode 100644
index 0000000..5153b00
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/math/util/ErrorMessagesTest.java
@@ -0,0 +1,30 @@
+// 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.math.util;
+
+import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import edu.wpi.first.wpilibj.UtilityClassTest;
+import edu.wpi.first.wpilibj.util.ErrorMessages;
+import org.junit.jupiter.api.Test;
+
+class ErrorMessagesTest extends UtilityClassTest<ErrorMessages> {
+ ErrorMessagesTest() {
+ super(ErrorMessages.class);
+ }
+
+ @Test
+ void requireNonNullParamNullTest() {
+ assertThrows(
+ NullPointerException.class, () -> requireNonNullParam(null, "testParam", "testMethod"));
+ }
+
+ @Test
+ void requireNonNullParamNotNullTest() {
+ assertDoesNotThrow(() -> requireNonNullParam("null", "testParam", "testMethod"));
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/AddressableLEDBufferTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/AddressableLEDBufferTest.java
index 0bd0113..2a24dbe 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/AddressableLEDBufferTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/AddressableLEDBufferTest.java
@@ -1,27 +1,22 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-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;
-
-import edu.wpi.first.wpilibj.util.Color;
-import edu.wpi.first.wpilibj.util.Color8Bit;
-
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.params.provider.Arguments.arguments;
+import edu.wpi.first.wpilibj.util.Color;
+import edu.wpi.first.wpilibj.util.Color8Bit;
+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 AddressableLEDBufferTest {
@ParameterizedTest
@MethodSource("hsvToRgbProvider")
@@ -32,8 +27,7 @@
assertAll(
() -> assertEquals((byte) r, buffer.m_buffer[2], "R value didn't match"),
() -> assertEquals((byte) g, buffer.m_buffer[1], "G value didn't match"),
- () -> assertEquals((byte) b, buffer.m_buffer[0], "B value didn't match")
- );
+ () -> assertEquals((byte) b, buffer.m_buffer[0], "B value didn't match"));
}
static Stream<Arguments> hsvToRgbProvider() {
@@ -54,7 +48,7 @@
arguments(150, 255, 128, 128, 0, 127), // Purple (ish)
arguments(90, 255, 128, 0, 127, 128), // Teal (ish)
arguments(120, 255, 128, 0, 0, 128) // Navy
- );
+ );
}
@Test
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/AnalogGyroTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/AnalogGyroTest.java
new file mode 100644
index 0000000..c8eaad9
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/AnalogGyroTest.java
@@ -0,0 +1,38 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.simulation.AnalogGyroSim;
+import org.junit.jupiter.api.Test;
+
+public class AnalogGyroTest {
+ @Test
+ void testInitializeWithAnalogInput() {
+ HAL.initialize(500, 0);
+ AnalogGyroSim sim = new AnalogGyroSim(0);
+ assertFalse(sim.getInitialized());
+
+ try (AnalogInput ai = new AnalogInput(0);
+ AnalogGyro gyro = new AnalogGyro(ai, 229, 17.4)) {
+ assertEquals(ai, gyro.getAnalogInput());
+ }
+ }
+
+ @Test
+ void testInitializeWithChannel() {
+ HAL.initialize(500, 0);
+ AnalogGyroSim sim = new AnalogGyroSim(0);
+ assertFalse(sim.getInitialized());
+
+ try (AnalogGyro gyro = new AnalogGyro(1, 191, 35.04)) {
+ assertNotNull(gyro.getAnalogInput());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/AnalogPotentiometerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/AnalogPotentiometerTest.java
new file mode 100644
index 0000000..fa299a5
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/AnalogPotentiometerTest.java
@@ -0,0 +1,104 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.simulation.AnalogInputSim;
+import edu.wpi.first.wpilibj.simulation.RoboRioSim;
+import org.junit.jupiter.api.Test;
+
+public class AnalogPotentiometerTest {
+ @Test
+ void testInitializeWithAnalogInput() {
+ HAL.initialize(500, 0);
+
+ try (AnalogInput ai = new AnalogInput(0);
+ AnalogPotentiometer pot = new AnalogPotentiometer(ai)) {
+ AnalogInputSim sim = new AnalogInputSim(ai);
+
+ RoboRioSim.resetData();
+ sim.setVoltage(4.0);
+ assertEquals(0.8, pot.get());
+ }
+ }
+
+ @Test
+ void testInitializeWithAnalogInputAndScale() {
+ HAL.initialize(500, 0);
+
+ try (AnalogInput ai = new AnalogInput(0);
+ AnalogPotentiometer pot = new AnalogPotentiometer(ai, 270.0)) {
+ RoboRioSim.resetData();
+ AnalogInputSim sim = new AnalogInputSim(ai);
+
+ sim.setVoltage(5.0);
+ assertEquals(270.0, pot.get());
+
+ sim.setVoltage(2.5);
+ assertEquals(135, pot.get());
+
+ sim.setVoltage(0.0);
+ assertEquals(0.0, pot.get());
+ }
+ }
+
+ @Test
+ void testInitializeWithChannel() {
+ HAL.initialize(500, 0);
+
+ try (AnalogPotentiometer pot = new AnalogPotentiometer(1)) {
+ RoboRioSim.resetData();
+ AnalogInputSim sim = new AnalogInputSim(1);
+
+ sim.setVoltage(5.0);
+ assertEquals(1.0, pot.get());
+ }
+ }
+
+ @Test
+ void testInitializeWithChannelAndScale() {
+ HAL.initialize(500, 0);
+
+ try (AnalogPotentiometer pot = new AnalogPotentiometer(1, 180.0)) {
+ RoboRioSim.resetData();
+ AnalogInputSim sim = new AnalogInputSim(1);
+
+ sim.setVoltage(5.0);
+ assertEquals(180.0, pot.get());
+
+ sim.setVoltage(0.0);
+ assertEquals(0.0, pot.get());
+ }
+ }
+
+ @Test
+ void testWithModifiedBatteryVoltage() {
+ try (AnalogPotentiometer pot = new AnalogPotentiometer(1, 180.0, 90.0)) {
+ RoboRioSim.resetData();
+ AnalogInputSim sim = new AnalogInputSim(1);
+
+ // Test at 5v
+ sim.setVoltage(5.0);
+ assertEquals(270, pot.get());
+
+ sim.setVoltage(0.0);
+ assertEquals(90, pot.get());
+
+ // Simulate a lower battery voltage
+ RoboRioSim.setUserVoltage5V(2.5);
+
+ sim.setVoltage(2.5);
+ assertEquals(270, pot.get());
+
+ sim.setVoltage(2.0);
+ assertEquals(234, pot.get());
+
+ sim.setVoltage(0.0);
+ assertEquals(90, pot.get());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/DebouncerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DebouncerTest.java
new file mode 100644
index 0000000..5a51f6c
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DebouncerTest.java
@@ -0,0 +1,54 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.wpilibj.simulation.SimHooks;
+import org.junit.jupiter.api.Test;
+
+public class DebouncerTest {
+ @Test
+ void debounceRisingTest() {
+ var debouncer = new Debouncer(0.02, Debouncer.DebounceType.kRising);
+
+ debouncer.calculate(false);
+ assertFalse(debouncer.calculate(true));
+
+ SimHooks.stepTiming(0.1);
+
+ assertTrue(debouncer.calculate(true));
+ }
+
+ @Test
+ void debounceFallingTest() {
+ var debouncer = new Debouncer(0.02, Debouncer.DebounceType.kFalling);
+
+ debouncer.calculate(true);
+ assertTrue(debouncer.calculate(false));
+
+ SimHooks.stepTiming(0.1);
+
+ assertFalse(debouncer.calculate(false));
+ }
+
+ @Test
+ void debounceBothTest() {
+ var debouncer = new Debouncer(0.02, Debouncer.DebounceType.kBoth);
+
+ debouncer.calculate(false);
+ assertFalse(debouncer.calculate(true));
+
+ SimHooks.stepTiming(0.1);
+
+ assertTrue(debouncer.calculate(true));
+ assertTrue(debouncer.calculate(false));
+
+ SimHooks.stepTiming(0.1);
+
+ assertFalse(debouncer.calculate(false));
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/DigitalOutputTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DigitalOutputTest.java
new file mode 100644
index 0000000..47b7eda
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DigitalOutputTest.java
@@ -0,0 +1,47 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+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 edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.simulation.DIOSim;
+import org.junit.jupiter.api.Test;
+
+public class DigitalOutputTest {
+ @Test
+ void testDefaultFunctions() {
+ try (DigitalOutput output = new DigitalOutput(0)) {
+ assertFalse(output.isAnalogTrigger());
+ assertEquals(0, output.getAnalogTriggerTypeForRouting());
+ assertFalse(output.isPulsing());
+ }
+ }
+
+ @Test
+ void testPwmFunctionsWithoutInitialization() {
+ HAL.initialize(500, 0);
+
+ try (DigitalOutput output = new DigitalOutput(0)) {
+ assertDoesNotThrow(() -> output.updateDutyCycle(0.6));
+ assertDoesNotThrow(output::disablePWM);
+ }
+ }
+
+ @Test
+ void testPwmFunctionsWithInitialization() {
+ HAL.initialize(500, 0);
+
+ try (DigitalOutput output = new DigitalOutput(0)) {
+ DIOSim sim = new DIOSim(output);
+ assertEquals(0, sim.getPulseLength());
+
+ output.enablePWM(0.5);
+ output.updateDutyCycle(0.6);
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/DoubleSolenoidTestCTRE.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DoubleSolenoidTestCTRE.java
new file mode 100644
index 0000000..72a3e89
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DoubleSolenoidTestCTRE.java
@@ -0,0 +1,94 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import edu.wpi.first.hal.util.AllocationException;
+import org.junit.jupiter.api.Test;
+
+public class DoubleSolenoidTestCTRE {
+ @Test
+ void testValidInitialization() {
+ try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.CTREPCM, 2, 3)) {
+ solenoid.set(DoubleSolenoid.Value.kReverse);
+ assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
+
+ solenoid.set(DoubleSolenoid.Value.kForward);
+ assertEquals(DoubleSolenoid.Value.kForward, solenoid.get());
+
+ solenoid.set(DoubleSolenoid.Value.kOff);
+ assertEquals(DoubleSolenoid.Value.kOff, solenoid.get());
+ }
+ }
+
+ @Test
+ void testThrowForwardPortAlreadyInitialized() {
+ try (
+ // Single solenoid that is reused for forward port
+ Solenoid solenoid = new Solenoid(5, PneumaticsModuleType.CTREPCM, 2)) {
+ assertThrows(
+ AllocationException.class,
+ () -> new DoubleSolenoid(5, PneumaticsModuleType.CTREPCM, 2, 3));
+ }
+ }
+
+ @Test
+ void testThrowReversePortAlreadyInitialized() {
+ try (
+ // Single solenoid that is reused for forward port
+ Solenoid solenoid = new Solenoid(6, PneumaticsModuleType.CTREPCM, 3)) {
+ assertThrows(
+ AllocationException.class,
+ () -> new DoubleSolenoid(6, PneumaticsModuleType.CTREPCM, 2, 3));
+ }
+ }
+
+ @Test
+ void testThrowBothPortsAlreadyInitialized() {
+ try (
+ // Single solenoid that is reused for forward port
+ Solenoid solenoid0 = new Solenoid(6, PneumaticsModuleType.CTREPCM, 2);
+ Solenoid solenoid1 = new Solenoid(6, PneumaticsModuleType.CTREPCM, 3)) {
+ assertThrows(
+ AllocationException.class,
+ () -> new DoubleSolenoid(6, PneumaticsModuleType.CTREPCM, 2, 3));
+ }
+ }
+
+ @Test
+ void testToggle() {
+ try (DoubleSolenoid solenoid = new DoubleSolenoid(4, PneumaticsModuleType.CTREPCM, 2, 3)) {
+ // Bootstrap it into reverse
+ solenoid.set(DoubleSolenoid.Value.kReverse);
+
+ solenoid.toggle();
+ assertEquals(DoubleSolenoid.Value.kForward, solenoid.get());
+
+ solenoid.toggle();
+ assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
+
+ // Of shouldn't do anything on toggle
+ solenoid.set(DoubleSolenoid.Value.kOff);
+ solenoid.toggle();
+ assertEquals(DoubleSolenoid.Value.kOff, solenoid.get());
+ }
+ }
+
+ @Test
+ void testInvalidForwardPort() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new DoubleSolenoid(0, PneumaticsModuleType.CTREPCM, 100, 1));
+ }
+
+ @Test
+ void testInvalidReversePort() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new DoubleSolenoid(0, PneumaticsModuleType.CTREPCM, 0, 100));
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/DoubleSolenoidTestREV.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DoubleSolenoidTestREV.java
new file mode 100644
index 0000000..888b677
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DoubleSolenoidTestREV.java
@@ -0,0 +1,91 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import edu.wpi.first.hal.util.AllocationException;
+import org.junit.jupiter.api.Test;
+
+public class DoubleSolenoidTestREV {
+ @Test
+ void testValidInitialization() {
+ try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.REVPH, 2, 3)) {
+ solenoid.set(DoubleSolenoid.Value.kReverse);
+ assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
+
+ solenoid.set(DoubleSolenoid.Value.kForward);
+ assertEquals(DoubleSolenoid.Value.kForward, solenoid.get());
+
+ solenoid.set(DoubleSolenoid.Value.kOff);
+ assertEquals(DoubleSolenoid.Value.kOff, solenoid.get());
+ }
+ }
+
+ @Test
+ void testThrowForwardPortAlreadyInitialized() {
+ try (
+ // Single solenoid that is reused for forward port
+ Solenoid solenoid = new Solenoid(5, PneumaticsModuleType.REVPH, 2)) {
+ assertThrows(
+ AllocationException.class, () -> new DoubleSolenoid(5, PneumaticsModuleType.REVPH, 2, 3));
+ }
+ }
+
+ @Test
+ void testThrowReversePortAlreadyInitialized() {
+ try (
+ // Single solenoid that is reused for forward port
+ Solenoid solenoid = new Solenoid(6, PneumaticsModuleType.REVPH, 3)) {
+ assertThrows(
+ AllocationException.class, () -> new DoubleSolenoid(6, PneumaticsModuleType.REVPH, 2, 3));
+ }
+ }
+
+ @Test
+ void testThrowBothPortsAlreadyInitialized() {
+ try (
+ // Single solenoid that is reused for forward port
+ Solenoid solenoid0 = new Solenoid(6, PneumaticsModuleType.REVPH, 2);
+ Solenoid solenoid1 = new Solenoid(6, PneumaticsModuleType.REVPH, 3)) {
+ assertThrows(
+ AllocationException.class, () -> new DoubleSolenoid(6, PneumaticsModuleType.REVPH, 2, 3));
+ }
+ }
+
+ @Test
+ void testToggle() {
+ try (DoubleSolenoid solenoid = new DoubleSolenoid(4, PneumaticsModuleType.REVPH, 2, 3)) {
+ // Bootstrap it into reverse
+ solenoid.set(DoubleSolenoid.Value.kReverse);
+
+ solenoid.toggle();
+ assertEquals(DoubleSolenoid.Value.kForward, solenoid.get());
+
+ solenoid.toggle();
+ assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
+
+ // Of shouldn't do anything on toggle
+ solenoid.set(DoubleSolenoid.Value.kOff);
+ solenoid.toggle();
+ assertEquals(DoubleSolenoid.Value.kOff, solenoid.get());
+ }
+ }
+
+ @Test
+ void testInvalidForwardPort() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new DoubleSolenoid(1, PneumaticsModuleType.REVPH, 100, 1));
+ }
+
+ @Test
+ void testInvalidReversePort() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new DoubleSolenoid(1, PneumaticsModuleType.REVPH, 0, 100));
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/DriverStationTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DriverStationTest.java
index 50e16c8..5a44615 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/DriverStationTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/DriverStationTest.java
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.stream.Stream;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+import edu.wpi.first.wpilibj.simulation.DriverStationSim;
+import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
-import edu.wpi.first.wpilibj.simulation.DriverStationSim;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.params.provider.Arguments.arguments;
-
class DriverStationTest {
@ParameterizedTest
@MethodSource("isConnectedProvider")
@@ -28,18 +23,17 @@
DriverStationSim.notifyNewData();
- assertEquals(expected, DriverStation.getInstance().isJoystickConnected(1));
+ assertEquals(expected, DriverStation.isJoystickConnected(1));
}
static Stream<Arguments> isConnectedProvider() {
return Stream.of(
- arguments(0, 0, 0, false),
- arguments(1, 0, 0, true),
- arguments(0, 1, 0, true),
- arguments(0, 0, 1, true),
- arguments(1, 1, 1, true),
- arguments(4, 10, 1, true)
- );
+ arguments(0, 0, 0, false),
+ arguments(1, 0, 0, true),
+ arguments(0, 1, 0, true),
+ arguments(0, 0, 1, true),
+ arguments(1, 1, 1, true),
+ arguments(4, 10, 1, true));
}
@MethodSource("connectionWarningProvider")
@@ -47,17 +41,15 @@
DriverStationSim.setFmsAttached(fms);
DriverStationSim.notifyNewData();
- DriverStation.getInstance().silenceJoystickConnectionWarning(silence);
- assertEquals(expected,
- DriverStation.getInstance().isJoystickConnectionWarningSilenced());
+ DriverStation.silenceJoystickConnectionWarning(silence);
+ assertEquals(expected, DriverStation.isJoystickConnectionWarningSilenced());
}
static Stream<Arguments> connectionWarningProvider() {
return Stream.of(
- arguments(false, true, true),
- arguments(false, false, false),
- arguments(true, true, false),
- arguments(true, false, false)
- );
+ arguments(false, true, true),
+ arguments(false, false, false),
+ arguments(true, true, false),
+ arguments(true, false, false));
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java
new file mode 100644
index 0000000..2eecd66
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java
@@ -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.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.wpilibj.simulation.DIOSim;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.jupiter.api.Test;
+
+public class InterruptTest {
+ @Test
+ void testAsynchronousInterrupt() {
+ AtomicBoolean hasFired = new AtomicBoolean(false);
+ AtomicInteger counter = new AtomicInteger(0);
+
+ try (DigitalInput di = new DigitalInput(0);
+ AsynchronousInterrupt interrupt =
+ new AsynchronousInterrupt(
+ di,
+ (a, b) -> {
+ counter.incrementAndGet();
+ hasFired.set(true);
+ })) {
+ interrupt.enable();
+ Timer.delay(0.5);
+ DIOSim digitalSim = new DIOSim(di);
+ digitalSim.setValue(false);
+ Timer.delay(0.01);
+ digitalSim.setValue(true);
+ Timer.delay(0.01);
+
+ int count = 0;
+ while (!hasFired.get()) {
+ Timer.delay(0.005);
+ count++;
+ assertTrue(count < 1000);
+ }
+ assertEquals(1, counter.get(), "The interrupt did not fire the expected number of times");
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/JoystickTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/JoystickTest.java
index 7b1cfbb..bc79d0d 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/JoystickTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/JoystickTest.java
@@ -1,18 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import org.junit.jupiter.api.Test;
+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.hal.HAL;
import edu.wpi.first.wpilibj.simulation.JoystickSim;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
class JoystickTest {
@Test
@@ -44,4 +42,132 @@
joysim.notifyNewData();
assertEquals(0.0, joy.getY(), 0.001);
}
+
+ @Test
+ void testGetZ() {
+ HAL.initialize(500, 0);
+ Joystick joy = new Joystick(1);
+ JoystickSim joysim = new JoystickSim(joy);
+
+ joysim.setZ(0.25);
+ joysim.notifyNewData();
+ assertEquals(0.25, joy.getZ(), 0.001);
+
+ joysim.setZ(0);
+ joysim.notifyNewData();
+ assertEquals(0.0, joy.getZ(), 0.001);
+ }
+
+ @Test
+ void testGetTwist() {
+ HAL.initialize(500, 0);
+ Joystick joy = new Joystick(1);
+ JoystickSim joysim = new JoystickSim(joy);
+
+ joysim.setTwist(0.25);
+ joysim.notifyNewData();
+ assertEquals(0.25, joy.getTwist(), 0.001);
+
+ joysim.setTwist(0);
+ joysim.notifyNewData();
+ assertEquals(0.0, joy.getTwist(), 0.001);
+ }
+
+ @Test
+ void testGetThrottle() {
+ HAL.initialize(500, 0);
+ Joystick joy = new Joystick(1);
+ JoystickSim joysim = new JoystickSim(joy);
+
+ joysim.setThrottle(0.25);
+ joysim.notifyNewData();
+ assertEquals(0.25, joy.getThrottle(), 0.001);
+
+ joysim.setThrottle(0);
+ joysim.notifyNewData();
+ assertEquals(0.0, joy.getThrottle(), 0.001);
+ }
+
+ @Test
+ void testGetTrigger() {
+ HAL.initialize(500, 0);
+ Joystick joy = new Joystick(1);
+ JoystickSim joysim = new JoystickSim(joy);
+
+ joysim.setTrigger(true);
+ joysim.notifyNewData();
+ assertTrue(joy.getTrigger());
+
+ joysim.setTrigger(false);
+ joysim.notifyNewData();
+ assertFalse(joy.getTrigger());
+ }
+
+ @Test
+ void testGetTop() {
+ HAL.initialize(500, 0);
+ Joystick joy = new Joystick(1);
+ JoystickSim joysim = new JoystickSim(joy);
+
+ joysim.setTop(true);
+ joysim.notifyNewData();
+ assertTrue(joy.getTop());
+
+ joysim.setTop(false);
+ joysim.notifyNewData();
+ assertFalse(joy.getTop());
+ }
+
+ @Test
+ void testGetMagnitude() {
+ HAL.initialize(500, 0);
+ Joystick joy = new Joystick(1);
+ JoystickSim joysim = new JoystickSim(joy);
+
+ // X Only
+ joysim.setX(0.5);
+ joysim.setY(0.0);
+ joysim.notifyNewData();
+ assertEquals(0.5, joy.getMagnitude(), 0.001);
+
+ // Y Only
+ joysim.setX(0.0);
+ joysim.setY(-0.5);
+ joysim.notifyNewData();
+ assertEquals(0.5, joy.getMagnitude(), 0.001);
+
+ // Both
+ joysim.setX(0.5);
+ joysim.setY(-0.5);
+ joysim.notifyNewData();
+ assertEquals(0.70710678118, joy.getMagnitude(), 0.001);
+ }
+
+ @Test
+ void testGetDirection() {
+ HAL.initialize(500, 0);
+ Joystick joy = new Joystick(1);
+ JoystickSim joysim = new JoystickSim(joy);
+
+ // X Only
+ joysim.setX(0.5);
+ joysim.setY(0.0);
+ joysim.notifyNewData();
+ assertEquals(90, joy.getDirectionDegrees(), 0.001);
+ assertEquals(Math.toRadians(90), joy.getDirectionRadians(), 0.001);
+
+ // Y Only
+ joysim.setX(0.0);
+ joysim.setY(-0.5);
+ joysim.notifyNewData();
+ assertEquals(0, joy.getDirectionDegrees(), 0.001);
+ assertEquals(Math.toRadians(0), joy.getDirectionRadians(), 0.001);
+
+ // Both
+ joysim.setX(0.5);
+ joysim.setY(-0.5);
+ joysim.notifyNewData();
+ assertEquals(45, joy.getDirectionDegrees(), 0.001);
+ assertEquals(Math.toRadians(45), joy.getDirectionRadians(), 0.001);
+ }
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockHardwareExtension.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockHardwareExtension.java
index 7406ca9..e70f182 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockHardwareExtension.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockHardwareExtension.java
@@ -1,19 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.simulation.DriverStationSim;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.simulation.DriverStationSim;
-
public final class MockHardwareExtension implements BeforeAllCallback {
private static ExtensionContext getRoot(ExtensionContext context) {
return context.getParent().map(MockHardwareExtension::getRoot).orElse(context);
@@ -21,10 +17,15 @@
@Override
public void beforeAll(ExtensionContext context) {
- getRoot(context).getStore(Namespace.GLOBAL).getOrComputeIfAbsent("HAL Initialized", key -> {
- initializeHardware();
- return true;
- }, Boolean.class);
+ getRoot(context)
+ .getStore(Namespace.GLOBAL)
+ .getOrComputeIfAbsent(
+ "HAL Initialized",
+ key -> {
+ initializeHardware();
+ return true;
+ },
+ Boolean.class);
}
private void initializeHardware() {
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockSpeedController.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockSpeedController.java
deleted file mode 100644
index d183723..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockSpeedController.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-public class MockSpeedController implements SpeedController {
- private double m_speed;
- private boolean m_isInverted;
-
- @Override
- public void set(double speed) {
- m_speed = m_isInverted ? -speed : speed;
- }
-
- @Override
- public double get() {
- return m_speed;
- }
-
- @Override
- public void setInverted(boolean isInverted) {
- m_isInverted = isInverted;
- }
-
- @Override
- public boolean getInverted() {
- return m_isInverted;
- }
-
- @Override
- public void disable() {
- m_speed = 0;
- }
-
- @Override
- public void stopMotor() {
- disable();
- }
-
- @Override
- public void pidWrite(double output) {
- set(output);
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/PS4ControllerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/PS4ControllerTest.java
new file mode 100644
index 0000000..e969cb3
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/PS4ControllerTest.java
@@ -0,0 +1,81 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+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.hal.HAL;
+import edu.wpi.first.wpilibj.simulation.PS4ControllerSim;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+class PS4ControllerTest {
+ @ParameterizedTest
+ @EnumSource(value = PS4Controller.Button.class)
+ @SuppressWarnings({"VariableDeclarationUsageDistance"})
+ public void testButtons(PS4Controller.Button button)
+ throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ HAL.initialize(500, 0);
+ PS4Controller joy = new PS4Controller(2);
+ PS4ControllerSim joysim = new PS4ControllerSim(joy);
+
+ var buttonName = button.toString();
+
+ String simSetMethodName = "set" + buttonName;
+ String joyGetMethodName = "get" + buttonName;
+ String joyPressedMethodName = "get" + buttonName + "Pressed";
+ String joyReleasedMethodName = "get" + buttonName + "Released";
+
+ Method simSetMethod = joysim.getClass().getMethod(simSetMethodName, boolean.class);
+ Method joyGetMethod = joy.getClass().getMethod(joyGetMethodName);
+ Method joyPressedMethod = joy.getClass().getMethod(joyPressedMethodName);
+ Method joyReleasedMethod = joy.getClass().getMethod(joyReleasedMethodName);
+
+ simSetMethod.invoke(joysim, false);
+ joysim.notifyNewData();
+ assertFalse((Boolean) joyGetMethod.invoke(joy));
+ // need to call pressed and released to clear flags
+ joyPressedMethod.invoke(joy);
+ joyReleasedMethod.invoke(joy);
+
+ simSetMethod.invoke(joysim, true);
+ joysim.notifyNewData();
+ assertTrue((Boolean) joyGetMethod.invoke(joy));
+ assertTrue((Boolean) joyPressedMethod.invoke(joy));
+ assertFalse((Boolean) joyReleasedMethod.invoke(joy));
+
+ simSetMethod.invoke(joysim, false);
+ joysim.notifyNewData();
+ assertFalse((Boolean) joyGetMethod.invoke(joy));
+ assertFalse((Boolean) joyPressedMethod.invoke(joy));
+ assertTrue((Boolean) joyReleasedMethod.invoke(joy));
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = PS4Controller.Axis.class)
+ @SuppressWarnings({"VariableDeclarationUsageDistance"})
+ public void testAxes(PS4Controller.Axis axis)
+ throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ HAL.initialize(500, 0);
+ PS4Controller joy = new PS4Controller(2);
+ PS4ControllerSim joysim = new PS4ControllerSim(joy);
+
+ var axisName = axis.toString();
+
+ String simSetMethodName = "set" + axisName;
+ String joyGetMethodName = "get" + axisName;
+
+ Method simSetMethod = joysim.getClass().getMethod(simSetMethodName, double.class);
+ Method joyGetMethod = joy.getClass().getMethod(joyGetMethodName);
+
+ simSetMethod.invoke(joysim, 0.35);
+ joysim.notifyNewData();
+ assertEquals(0.35, (Double) joyGetMethod.invoke(joy), 0.001);
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/PreferencesTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/PreferencesTest.java
index 7b3735f..2603d5b 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/PreferencesTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/PreferencesTest.java
@@ -1,12 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
+import static org.junit.jupiter.api.Assertions.assertAll;
+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 static org.junit.jupiter.api.Assertions.fail;
+
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableInstance;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
@@ -14,7 +19,6 @@
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Stream;
-
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
@@ -25,15 +29,6 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
-import edu.wpi.first.networktables.NetworkTable;
-import edu.wpi.first.networktables.NetworkTableInstance;
-
-import static org.junit.jupiter.api.Assertions.assertAll;
-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 static org.junit.jupiter.api.Assertions.fail;
-
class PreferencesTest {
private final Preferences m_prefs = Preferences.getInstance();
private final NetworkTable m_table = NetworkTableInstance.getDefault().getTable("Preferences");
@@ -76,8 +71,9 @@
Set<String> keys = m_table.getKeys();
keys.remove(".type");
- assertTrue(keys.isEmpty(), "Preferences was not empty! Preferences in table: "
- + Arrays.toString(keys.toArray()));
+ assertTrue(
+ keys.isEmpty(),
+ "Preferences was not empty! Preferences in table: " + Arrays.toString(keys.toArray()));
}
@ParameterizedTest
@@ -99,9 +95,8 @@
() -> assertEquals(0.2, m_prefs.getDouble("checkedValueDouble", 0), 1e-6),
() -> assertEquals("Hello. How are you?", m_prefs.getString("checkedValueString", "")),
() -> assertEquals(2, m_prefs.getInt("checkedValueInt", 0)),
- () -> assertEquals(3.14, m_prefs.getFloat("checkedValueFloat", 0), 1e-6),
- () -> assertFalse(m_prefs.getBoolean("checkedValueBoolean", true))
- );
+ () -> assertEquals(3.4, m_prefs.getFloat("checkedValueFloat", 0), 1e-6),
+ () -> assertFalse(m_prefs.getBoolean("checkedValueBoolean", true)));
}
@Test
@@ -114,8 +109,7 @@
() -> assertEquals("", m_prefs.getString("checkedValueString", "")),
() -> assertEquals(0, m_prefs.getInt("checkedValueInt", 0)),
() -> assertEquals(0, m_prefs.getFloat("checkedValueFloat", 0), 1e-6),
- () -> assertTrue(m_prefs.getBoolean("checkedValueBoolean", true))
- );
+ () -> assertTrue(m_prefs.getBoolean("checkedValueBoolean", true)));
}
@Nested
@@ -129,8 +123,7 @@
assertAll(
() -> assertEquals(value, m_prefs.getInt(key, -1)),
- () -> assertEquals(value, m_table.getEntry(key).getNumber(-1).intValue())
- );
+ () -> assertEquals(value, m_table.getEntry(key).getNumber(-1).intValue()));
}
@Test
@@ -142,8 +135,7 @@
assertAll(
() -> assertEquals(value, m_prefs.getLong(key, -1)),
- () -> assertEquals(value, m_table.getEntry(key).getNumber(-1).longValue())
- );
+ () -> assertEquals(value, m_table.getEntry(key).getNumber(-1).longValue()));
}
@Test
@@ -155,8 +147,7 @@
assertAll(
() -> assertEquals(value, m_prefs.getFloat(key, -1), 1e-6),
- () -> assertEquals(value, m_table.getEntry(key).getNumber(-1).floatValue(), 1e-6)
- );
+ () -> assertEquals(value, m_table.getEntry(key).getNumber(-1).floatValue(), 1e-6));
}
@Test
@@ -168,8 +159,7 @@
assertAll(
() -> assertEquals(value, m_prefs.getDouble(key, -1), 1e-6),
- () -> assertEquals(value, m_table.getEntry(key).getNumber(-1).doubleValue(), 1e-6)
- );
+ () -> assertEquals(value, m_table.getEntry(key).getNumber(-1).doubleValue(), 1e-6));
}
@Test
@@ -181,8 +171,7 @@
assertAll(
() -> assertEquals(value, m_prefs.getString(key, "")),
- () -> assertEquals(value, m_table.getEntry(key).getString(""))
- );
+ () -> assertEquals(value, m_table.getEntry(key).getString("")));
}
@Test
@@ -194,8 +183,7 @@
assertAll(
() -> assertEquals(value, m_prefs.getBoolean(key, false)),
- () -> assertEquals(value, m_table.getEntry(key).getBoolean(false))
- );
+ () -> assertEquals(value, m_table.getEntry(key).getBoolean(false)));
}
}
@@ -206,7 +194,6 @@
"checkedValueString",
"checkedValueInt",
"checkedValueFloat",
- "checkedValueBoolean"
- );
+ "checkedValueBoolean");
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/RobotControllerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/RobotControllerTest.java
index 4bce18f..3c5647c 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/RobotControllerTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/RobotControllerTest.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/SensorUtilTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/SensorUtilTest.java
new file mode 100644
index 0000000..a33716c
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/SensorUtilTest.java
@@ -0,0 +1,42 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class SensorUtilTest {
+ @Test
+ void checkAnalogInputChannel() {
+ assertThrows(IllegalArgumentException.class, () -> SensorUtil.checkAnalogInputChannel(100));
+ }
+
+ @Test
+ void checkAnalogOutputChannel() {
+ assertThrows(IllegalArgumentException.class, () -> SensorUtil.checkAnalogOutputChannel(100));
+ }
+
+ @Test
+ void testInvalidDigitalChannel() {
+ assertThrows(IllegalArgumentException.class, () -> SensorUtil.checkDigitalChannel(100));
+ }
+
+ @Test
+ void testInvalidPwmChannel() {
+ assertThrows(IllegalArgumentException.class, () -> SensorUtil.checkPWMChannel(100));
+ }
+
+ @Test
+ void testInvalidRelayModule() {
+ assertThrows(IllegalArgumentException.class, () -> SensorUtil.checkRelayChannel(100));
+ }
+
+ @Test
+ void testgetDefaultCtrePcmModule() {
+ assertEquals(0, SensorUtil.getDefaultCTREPCMModule());
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/SlewRateLimiterTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/SlewRateLimiterTest.java
deleted file mode 100644
index e47b70b..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/SlewRateLimiterTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-public class SlewRateLimiterTest {
- @Test
- void slewRateLimitTest() {
- SlewRateLimiter limiter = new SlewRateLimiter(1);
- Timer.delay(1);
- assertTrue(limiter.calculate(2) < 2);
- }
-
- @Test
- void slewRateNoLimitTest() {
- SlewRateLimiter limiter = new SlewRateLimiter(1);
- Timer.delay(1);
- assertEquals(limiter.calculate(0.5), 0.5);
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/SolenoidTestCTRE.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/SolenoidTestCTRE.java
new file mode 100644
index 0000000..0077650
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/SolenoidTestCTRE.java
@@ -0,0 +1,64 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.hal.util.AllocationException;
+import org.junit.jupiter.api.Test;
+
+public class SolenoidTestCTRE {
+ @Test
+ void testValidInitialization() {
+ try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
+ assertEquals(2, solenoid.getChannel());
+
+ solenoid.set(true);
+ assertTrue(solenoid.get());
+
+ solenoid.set(false);
+ assertFalse(solenoid.get());
+ }
+ }
+
+ @Test
+ void testDoubleInitialization() {
+ try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
+ assertThrows(
+ AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 2));
+ }
+ }
+
+ @Test
+ void testDoubleInitializationFromDoubleSolenoid() {
+ try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.CTREPCM, 2, 3)) {
+ assertThrows(
+ AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 2));
+ }
+ }
+
+ @Test
+ void testInvalidChannel() {
+ assertThrows(
+ IllegalArgumentException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 100));
+ }
+
+ @Test
+ void testToggle() {
+ try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
+ solenoid.set(true);
+ assertTrue(solenoid.get());
+
+ solenoid.toggle();
+ assertFalse(solenoid.get());
+
+ solenoid.toggle();
+ assertTrue(solenoid.get());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/SolenoidTestREV.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/SolenoidTestREV.java
new file mode 100644
index 0000000..3f07406
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/SolenoidTestREV.java
@@ -0,0 +1,62 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.hal.util.AllocationException;
+import org.junit.jupiter.api.Test;
+
+public class SolenoidTestREV {
+ @Test
+ void testValidInitialization() {
+ try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
+ assertEquals(2, solenoid.getChannel());
+
+ solenoid.set(true);
+ assertTrue(solenoid.get());
+
+ solenoid.set(false);
+ assertFalse(solenoid.get());
+ }
+ }
+
+ @Test
+ void testDoubleInitialization() {
+ try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
+ assertThrows(AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 2));
+ }
+ }
+
+ @Test
+ void testDoubleInitializationFromDoubleSolenoid() {
+ try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.REVPH, 2, 3)) {
+ assertThrows(AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 2));
+ }
+ }
+
+ @Test
+ void testInvalidChannel() {
+ assertThrows(
+ IllegalArgumentException.class, () -> new Solenoid(3, PneumaticsModuleType.REVPH, 100));
+ }
+
+ @Test
+ void testToggle() {
+ try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.REVPH, 2)) {
+ solenoid.set(true);
+ assertTrue(solenoid.get());
+
+ solenoid.toggle();
+ assertFalse(solenoid.get());
+
+ solenoid.toggle();
+ assertTrue(solenoid.get());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/SpeedControllerGroupTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/SpeedControllerGroupTest.java
deleted file mode 100644
index 62e2f46..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/SpeedControllerGroupTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj;
-
-import java.util.Arrays;
-import java.util.stream.DoubleStream;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-class SpeedControllerGroupTest {
- private static Stream<Arguments> speedControllerArguments() {
- return IntStream.of(1, 2, 3).mapToObj(number -> {
- SpeedController[] speedControllers = Stream.generate(MockSpeedController::new)
- .limit(number)
- .toArray(SpeedController[]::new);
- SpeedControllerGroup group = new SpeedControllerGroup(speedControllers[0],
- Arrays.copyOfRange(speedControllers, 1, speedControllers.length));
- return Arguments.of(group, speedControllers);
- });
- }
-
- @ParameterizedTest
- @MethodSource("speedControllerArguments")
- void setTest(final SpeedControllerGroup group, final SpeedController[] speedControllers) {
- group.set(1.0);
-
- assertArrayEquals(DoubleStream.generate(() -> 1.0).limit(speedControllers.length).toArray(),
- Arrays.stream(speedControllers).mapToDouble(SpeedController::get).toArray(),
- 0.00005);
- }
-
- @ParameterizedTest
- @MethodSource("speedControllerArguments")
- void getInvertedTest(final SpeedControllerGroup group,
- final SpeedController[] speedControllers) {
- group.setInverted(true);
-
- assertTrue(group.getInverted());
- }
-
- @ParameterizedTest
- @MethodSource("speedControllerArguments")
- void setInvertedDoesNotModifySpeedControllersTest(final SpeedControllerGroup group,
- final SpeedController[] speedControllers) {
- group.setInverted(true);
-
- assertArrayEquals(Stream.generate(() -> false).limit(speedControllers.length).toArray(),
- Arrays.stream(speedControllers).map(SpeedController::getInverted).toArray());
- }
-
- @ParameterizedTest
- @MethodSource("speedControllerArguments")
- void setInvertedDoesInvertTest(final SpeedControllerGroup group,
- final SpeedController[] speedControllers) {
- group.setInverted(true);
- group.set(1.0);
-
- assertArrayEquals(DoubleStream.generate(() -> -1.0).limit(speedControllers.length).toArray(),
- Arrays.stream(speedControllers).mapToDouble(SpeedController::get).toArray(),
- 0.00005);
- }
-
- @ParameterizedTest
- @MethodSource("speedControllerArguments")
- void disableTest(final SpeedControllerGroup group,
- final SpeedController[] speedControllers) {
- group.set(1.0);
- group.disable();
-
- assertArrayEquals(DoubleStream.generate(() -> 0.0).limit(speedControllers.length).toArray(),
- Arrays.stream(speedControllers).mapToDouble(SpeedController::get).toArray(),
- 0.00005);
- }
-
- @ParameterizedTest
- @MethodSource("speedControllerArguments")
- void stopMotorTest(final SpeedControllerGroup group,
- final SpeedController[] speedControllers) {
- group.set(1.0);
- group.stopMotor();
-
- assertArrayEquals(DoubleStream.generate(() -> 0.0).limit(speedControllers.length).toArray(),
- Arrays.stream(speedControllers).mapToDouble(SpeedController::get).toArray(),
- 0.00005);
- }
-
- @ParameterizedTest
- @MethodSource("speedControllerArguments")
- void pidWriteTest(final SpeedControllerGroup group,
- final SpeedController[] speedControllers) {
- group.pidWrite(1.0);
-
- assertArrayEquals(DoubleStream.generate(() -> 1.0).limit(speedControllers.length).toArray(),
- Arrays.stream(speedControllers).mapToDouble(SpeedController::get).toArray(),
- 0.00005);
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimedRobotTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimedRobotTest.java
index 6942ca0..de5fd1c 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimedRobotTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimedRobotTest.java
@@ -1,26 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.concurrent.atomic.AtomicInteger;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import edu.wpi.first.wpilibj.simulation.DriverStationSim;
+import edu.wpi.first.wpilibj.simulation.SimHooks;
+import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.ResourceLock;
-import edu.wpi.first.wpilibj.simulation.DriverStationSim;
-import edu.wpi.first.wpilibj.simulation.SimHooks;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
class TimedRobotTest {
- class MockRobot extends TimedRobot {
+ static class MockRobot extends TimedRobot {
public final AtomicInteger m_robotInitCount = new AtomicInteger(0);
public final AtomicInteger m_simulationInitCount = new AtomicInteger(0);
public final AtomicInteger m_disabledInitCount = new AtomicInteger(0);
@@ -35,6 +30,11 @@
public final AtomicInteger m_teleopPeriodicCount = new AtomicInteger(0);
public final AtomicInteger m_testPeriodicCount = new AtomicInteger(0);
+ public final AtomicInteger m_disabledExitCount = new AtomicInteger(0);
+ public final AtomicInteger m_autonomousExitCount = new AtomicInteger(0);
+ public final AtomicInteger m_teleopExitCount = new AtomicInteger(0);
+ public final AtomicInteger m_testExitCount = new AtomicInteger(0);
+
@Override
public void robotInit() {
m_robotInitCount.addAndGet(1);
@@ -94,6 +94,26 @@
public void testPeriodic() {
m_testPeriodicCount.addAndGet(1);
}
+
+ @Override
+ public void disabledExit() {
+ m_disabledExitCount.addAndGet(1);
+ }
+
+ @Override
+ public void autonomousExit() {
+ m_autonomousExitCount.addAndGet(1);
+ }
+
+ @Override
+ public void teleopExit() {
+ m_teleopExitCount.addAndGet(1);
+ }
+
+ @Override
+ public void testExit() {
+ m_testExitCount.addAndGet(1);
+ }
}
@BeforeEach
@@ -108,17 +128,19 @@
@Test
@ResourceLock("timing")
- void disabledTest() {
+ void disabledModeTest() {
MockRobot robot = new MockRobot();
- Thread robotThread = new Thread(() -> {
- robot.startCompetition();
- });
+ Thread robotThread =
+ new Thread(
+ () -> {
+ robot.startCompetition();
+ });
robotThread.start();
DriverStationSim.setEnabled(false);
DriverStationSim.notifyNewData();
- SimHooks.stepTiming(0.0); // Wait for Notifiers
+ SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(1, robot.m_robotInitCount.get());
assertEquals(1, robot.m_simulationInitCount.get());
@@ -134,6 +156,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
SimHooks.stepTiming(0.02);
assertEquals(1, robot.m_robotInitCount.get());
@@ -150,6 +177,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
SimHooks.stepTiming(0.02);
assertEquals(1, robot.m_robotInitCount.get());
@@ -166,6 +198,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
robot.endCompetition();
try {
robotThread.interrupt();
@@ -178,19 +215,21 @@
@Test
@ResourceLock("timing")
- void autonomousTest() {
+ void autonomousModeTest() {
MockRobot robot = new MockRobot();
- Thread robotThread = new Thread(() -> {
- robot.startCompetition();
- });
+ Thread robotThread =
+ new Thread(
+ () -> {
+ robot.startCompetition();
+ });
robotThread.start();
DriverStationSim.setEnabled(true);
DriverStationSim.setAutonomous(true);
DriverStationSim.setTest(false);
DriverStationSim.notifyNewData();
- SimHooks.stepTiming(0.0); // Wait for Notifiers
+ SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(1, robot.m_robotInitCount.get());
assertEquals(1, robot.m_simulationInitCount.get());
@@ -206,6 +245,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
SimHooks.stepTiming(0.02);
assertEquals(1, robot.m_robotInitCount.get());
@@ -222,6 +266,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
SimHooks.stepTiming(0.02);
assertEquals(1, robot.m_robotInitCount.get());
@@ -238,6 +287,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
robot.endCompetition();
try {
robotThread.interrupt();
@@ -250,19 +304,21 @@
@Test
@ResourceLock("timing")
- void teleopTest() {
+ void teleopModeTest() {
MockRobot robot = new MockRobot();
- Thread robotThread = new Thread(() -> {
- robot.startCompetition();
- });
+ Thread robotThread =
+ new Thread(
+ () -> {
+ robot.startCompetition();
+ });
robotThread.start();
DriverStationSim.setEnabled(true);
DriverStationSim.setAutonomous(false);
DriverStationSim.setTest(false);
DriverStationSim.notifyNewData();
- SimHooks.stepTiming(0.0); // Wait for Notifiers
+ SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(1, robot.m_robotInitCount.get());
assertEquals(1, robot.m_simulationInitCount.get());
@@ -278,6 +334,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
SimHooks.stepTiming(0.02);
assertEquals(1, robot.m_robotInitCount.get());
@@ -294,6 +355,11 @@
assertEquals(1, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
SimHooks.stepTiming(0.02);
assertEquals(1, robot.m_robotInitCount.get());
@@ -310,6 +376,11 @@
assertEquals(2, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
robot.endCompetition();
try {
robotThread.interrupt();
@@ -322,19 +393,21 @@
@Test
@ResourceLock("timing")
- void testTest() {
+ void testModeTest() {
MockRobot robot = new MockRobot();
- Thread robotThread = new Thread(() -> {
- robot.startCompetition();
- });
+ Thread robotThread =
+ new Thread(
+ () -> {
+ robot.startCompetition();
+ });
robotThread.start();
DriverStationSim.setEnabled(true);
DriverStationSim.setAutonomous(false);
DriverStationSim.setTest(true);
DriverStationSim.notifyNewData();
- SimHooks.stepTiming(0.0); // Wait for Notifiers
+ SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(1, robot.m_robotInitCount.get());
assertEquals(1, robot.m_simulationInitCount.get());
@@ -350,6 +423,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(0, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
SimHooks.stepTiming(0.02);
assertEquals(1, robot.m_robotInitCount.get());
@@ -366,6 +444,11 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(1, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
SimHooks.stepTiming(0.02);
assertEquals(1, robot.m_robotInitCount.get());
@@ -382,6 +465,134 @@
assertEquals(0, robot.m_teleopPeriodicCount.get());
assertEquals(2, robot.m_testPeriodicCount.get());
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
+ robot.endCompetition();
+ try {
+ robotThread.interrupt();
+ robotThread.join();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ robot.close();
+ }
+
+ @Test
+ @ResourceLock("timing")
+ void modeChangeTest() {
+ MockRobot robot = new MockRobot();
+
+ Thread robotThread =
+ new Thread(
+ () -> {
+ robot.startCompetition();
+ });
+ robotThread.start();
+
+ // Start in disabled
+ DriverStationSim.setEnabled(false);
+ DriverStationSim.setAutonomous(false);
+ DriverStationSim.setTest(false);
+ DriverStationSim.notifyNewData();
+ SimHooks.stepTiming(0.0); // Wait for Notifiers
+
+ assertEquals(0, robot.m_disabledInitCount.get());
+ assertEquals(0, robot.m_autonomousInitCount.get());
+ assertEquals(0, robot.m_teleopInitCount.get());
+ assertEquals(0, robot.m_testInitCount.get());
+
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
+ SimHooks.stepTiming(0.02);
+
+ assertEquals(1, robot.m_disabledInitCount.get());
+ assertEquals(0, robot.m_autonomousInitCount.get());
+ assertEquals(0, robot.m_teleopInitCount.get());
+ assertEquals(0, robot.m_testInitCount.get());
+
+ assertEquals(0, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
+ // Transition to autonomous
+ DriverStationSim.setEnabled(true);
+ DriverStationSim.setAutonomous(true);
+ DriverStationSim.setTest(false);
+ DriverStationSim.notifyNewData();
+
+ SimHooks.stepTiming(0.02);
+
+ assertEquals(1, robot.m_disabledInitCount.get());
+ assertEquals(1, robot.m_autonomousInitCount.get());
+ assertEquals(0, robot.m_teleopInitCount.get());
+ assertEquals(0, robot.m_testInitCount.get());
+
+ assertEquals(1, robot.m_disabledExitCount.get());
+ assertEquals(0, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
+ // Transition to teleop
+ DriverStationSim.setEnabled(true);
+ DriverStationSim.setAutonomous(false);
+ DriverStationSim.setTest(false);
+ DriverStationSim.notifyNewData();
+
+ SimHooks.stepTiming(0.02);
+
+ assertEquals(1, robot.m_disabledInitCount.get());
+ assertEquals(1, robot.m_autonomousInitCount.get());
+ assertEquals(1, robot.m_teleopInitCount.get());
+ assertEquals(0, robot.m_testInitCount.get());
+
+ assertEquals(1, robot.m_disabledExitCount.get());
+ assertEquals(1, robot.m_autonomousExitCount.get());
+ assertEquals(0, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
+ // Transition to test
+ DriverStationSim.setEnabled(true);
+ DriverStationSim.setAutonomous(false);
+ DriverStationSim.setTest(true);
+ DriverStationSim.notifyNewData();
+
+ SimHooks.stepTiming(0.02);
+
+ assertEquals(1, robot.m_disabledInitCount.get());
+ assertEquals(1, robot.m_autonomousInitCount.get());
+ assertEquals(1, robot.m_teleopInitCount.get());
+ assertEquals(1, robot.m_testInitCount.get());
+
+ assertEquals(1, robot.m_disabledExitCount.get());
+ assertEquals(1, robot.m_autonomousExitCount.get());
+ assertEquals(1, robot.m_teleopExitCount.get());
+ assertEquals(0, robot.m_testExitCount.get());
+
+ // Transition to disabled
+ DriverStationSim.setEnabled(false);
+ DriverStationSim.setAutonomous(false);
+ DriverStationSim.setTest(false);
+ DriverStationSim.notifyNewData();
+
+ SimHooks.stepTiming(0.02);
+
+ assertEquals(2, robot.m_disabledInitCount.get());
+ assertEquals(1, robot.m_autonomousInitCount.get());
+ assertEquals(1, robot.m_teleopInitCount.get());
+ assertEquals(1, robot.m_testInitCount.get());
+
+ assertEquals(1, robot.m_disabledExitCount.get());
+ assertEquals(1, robot.m_autonomousExitCount.get());
+ assertEquals(1, robot.m_teleopExitCount.get());
+ assertEquals(1, robot.m_testExitCount.get());
+
robot.endCompetition();
try {
robotThread.interrupt();
@@ -398,18 +609,22 @@
MockRobot robot = new MockRobot();
final AtomicInteger callbackCount = new AtomicInteger(0);
- robot.addPeriodic(() -> {
- callbackCount.addAndGet(1);
- }, 0.01);
+ robot.addPeriodic(
+ () -> {
+ callbackCount.addAndGet(1);
+ },
+ 0.01);
- Thread robotThread = new Thread(() -> {
- robot.startCompetition();
- });
+ Thread robotThread =
+ new Thread(
+ () -> {
+ robot.startCompetition();
+ });
robotThread.start();
DriverStationSim.setEnabled(false);
DriverStationSim.notifyNewData();
- SimHooks.stepTiming(0.0); // Wait for Notifiers
+ SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(0, robot.m_disabledInitCount.get());
assertEquals(0, robot.m_disabledPeriodicCount.get());
@@ -443,9 +658,12 @@
MockRobot robot = new MockRobot();
final AtomicInteger callbackCount = new AtomicInteger(0);
- robot.addPeriodic(() -> {
- callbackCount.addAndGet(1);
- }, 0.01, 0.005);
+ robot.addPeriodic(
+ () -> {
+ callbackCount.addAndGet(1);
+ },
+ 0.01,
+ 0.005);
// Expirations in this test (ms)
//
@@ -454,14 +672,16 @@
// 20 | 15
// 40 | 25
- Thread robotThread = new Thread(() -> {
- robot.startCompetition();
- });
+ Thread robotThread =
+ new Thread(
+ () -> {
+ robot.startCompetition();
+ });
robotThread.start();
DriverStationSim.setEnabled(false);
DriverStationSim.notifyNewData();
- SimHooks.stepTiming(0.0); // Wait for Notifiers
+ SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(0, robot.m_disabledInitCount.get());
assertEquals(0, robot.m_disabledPeriodicCount.get());
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimerTest.java
new file mode 100644
index 0000000..89619dd
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimerTest.java
@@ -0,0 +1,132 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+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.hal.HAL;
+import edu.wpi.first.wpilibj.simulation.SimHooks;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.ResourceLock;
+
+class TimerTest {
+ @BeforeEach
+ void setup() {
+ HAL.initialize(500, 0);
+ SimHooks.pauseTiming();
+ SimHooks.restartTiming();
+ }
+
+ @AfterEach
+ void cleanup() {
+ SimHooks.resumeTiming();
+ }
+
+ @Test
+ @ResourceLock("timing")
+ void startStopTest() {
+ var timer = new Timer();
+
+ // Verify timer is initialized as stopped
+ assertEquals(timer.get(), 0.0);
+ SimHooks.stepTiming(0.5);
+ assertEquals(timer.get(), 0.0);
+
+ // Verify timer increments after it's started
+ timer.start();
+ SimHooks.stepTiming(0.5);
+ assertEquals(timer.get(), 0.5, 1e-9);
+
+ // Verify timer stops incrementing after it's stopped
+ timer.stop();
+ SimHooks.stepTiming(0.5);
+ assertEquals(timer.get(), 0.5, 1e-9);
+ }
+
+ @Test
+ @ResourceLock("timing")
+ void resetTest() {
+ var timer = new Timer();
+ timer.start();
+
+ // Advance timer to 500 ms
+ assertEquals(timer.get(), 0.0);
+ SimHooks.stepTiming(0.5);
+ assertEquals(timer.get(), 0.5, 1e-9);
+
+ // Verify timer reports 0 ms after reset
+ timer.reset();
+ assertEquals(timer.get(), 0.0);
+
+ // Verify timer continues incrementing
+ SimHooks.stepTiming(0.5);
+ assertEquals(timer.get(), 0.5, 1e-9);
+
+ // Verify timer doesn't start incrementing after reset if it was stopped
+ timer.stop();
+ timer.reset();
+ SimHooks.stepTiming(0.5);
+ assertEquals(timer.get(), 0.0);
+ }
+
+ @Test
+ @ResourceLock("timing")
+ void hasElapsedTest() {
+ var timer = new Timer();
+
+ // Verify 0 ms has elapsed since timer hasn't started
+ assertTrue(timer.hasElapsed(0.0));
+
+ // Verify timer doesn't report elapsed time when stopped
+ SimHooks.stepTiming(0.5);
+ assertFalse(timer.hasElapsed(0.4));
+
+ timer.start();
+
+ // Verify timer reports >= 400 ms has elapsed after multiple calls
+ SimHooks.stepTiming(0.5);
+ assertTrue(timer.hasElapsed(0.4));
+ assertTrue(timer.hasElapsed(0.4));
+ }
+
+ @Test
+ @ResourceLock("timing")
+ void advanceIfElapsedTest() {
+ var timer = new Timer();
+
+ // Verify 0 ms has elapsed since timer hasn't started
+ assertTrue(timer.advanceIfElapsed(0.0));
+
+ // Verify timer doesn't report elapsed time when stopped
+ SimHooks.stepTiming(0.5);
+ assertFalse(timer.advanceIfElapsed(0.4));
+
+ timer.start();
+
+ // Verify timer reports >= 400 ms has elapsed for only first call
+ SimHooks.stepTiming(0.5);
+ assertTrue(timer.advanceIfElapsed(0.4));
+ assertFalse(timer.advanceIfElapsed(0.4));
+
+ // Verify timer reports >= 400 ms has elapsed for two calls
+ SimHooks.stepTiming(1.0);
+ assertTrue(timer.advanceIfElapsed(0.4));
+ assertTrue(timer.advanceIfElapsed(0.4));
+ assertFalse(timer.advanceIfElapsed(0.4));
+ }
+
+ @Test
+ @ResourceLock("timing")
+ void getFPGATimestampTest() {
+ double start = Timer.getFPGATimestamp();
+ SimHooks.stepTiming(0.5);
+ double end = Timer.getFPGATimestamp();
+ assertEquals(start + 0.5, end, 1e-9);
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimesliceRobotTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimesliceRobotTest.java
new file mode 100644
index 0000000..ee4860d
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/TimesliceRobotTest.java
@@ -0,0 +1,131 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import edu.wpi.first.wpilibj.simulation.DriverStationSim;
+import edu.wpi.first.wpilibj.simulation.SimHooks;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.ResourceLock;
+
+class TimesliceRobotTest {
+ static class MockRobot extends TimesliceRobot {
+ public final AtomicInteger m_robotPeriodicCount = new AtomicInteger(0);
+
+ MockRobot() {
+ super(0.002, 0.005);
+ }
+
+ @Override
+ public void robotPeriodic() {
+ m_robotPeriodicCount.addAndGet(1);
+ }
+ }
+
+ @BeforeEach
+ void setup() {
+ SimHooks.pauseTiming();
+ }
+
+ @AfterEach
+ void cleanup() {
+ SimHooks.resumeTiming();
+ }
+
+ @Test
+ @ResourceLock("timing")
+ void scheduleTest() {
+ MockRobot robot = new MockRobot();
+
+ final AtomicInteger callbackCount1 = new AtomicInteger(0);
+ final AtomicInteger callbackCount2 = new AtomicInteger(0);
+
+ // Timeslice allocation table
+ //
+ // | Name | Offset (ms) | Allocation (ms)|
+ // |-----------------|-------------|----------------|
+ // | RobotPeriodic() | 0 | 2 |
+ // | Callback 1 | 2 | 0.5 |
+ // | Callback 2 | 2.5 | 1 |
+ robot.schedule(
+ () -> {
+ callbackCount1.addAndGet(1);
+ },
+ 0.0005);
+ robot.schedule(
+ () -> {
+ callbackCount2.addAndGet(1);
+ },
+ 0.001);
+
+ Thread robotThread =
+ new Thread(
+ () -> {
+ robot.startCompetition();
+ });
+ robotThread.start();
+
+ DriverStationSim.setEnabled(false);
+ DriverStationSim.notifyNewData();
+ SimHooks.stepTiming(0.0); // Wait for Notifiers
+
+ // Functions scheduled with addPeriodic() are delayed by one period before
+ // their first run (5 ms for this test's callbacks here and 20 ms for
+ // robotPeriodic()).
+ SimHooks.stepTiming(0.005);
+
+ assertEquals(0, robot.m_robotPeriodicCount.get());
+ assertEquals(0, callbackCount1.get());
+ assertEquals(0, callbackCount2.get());
+
+ // Step to 1.5 ms
+ SimHooks.stepTiming(0.0015);
+ assertEquals(0, robot.m_robotPeriodicCount.get());
+ assertEquals(0, callbackCount1.get());
+ assertEquals(0, callbackCount2.get());
+
+ // Step to 2.25 ms
+ SimHooks.stepTiming(0.00075);
+ assertEquals(0, robot.m_robotPeriodicCount.get());
+ assertEquals(1, callbackCount1.get());
+ assertEquals(0, callbackCount2.get());
+
+ // Step to 2.75 ms
+ SimHooks.stepTiming(0.0005);
+ assertEquals(0, robot.m_robotPeriodicCount.get());
+ assertEquals(1, callbackCount1.get());
+ assertEquals(1, callbackCount2.get());
+
+ robot.endCompetition();
+ try {
+ robotThread.interrupt();
+ robotThread.join();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ robot.close();
+ }
+
+ @Test
+ @ResourceLock("timing")
+ void scheduleOverrunTest() {
+ MockRobot robot = new MockRobot();
+
+ robot.schedule(() -> {}, 0.0005);
+ robot.schedule(() -> {}, 0.001);
+
+ // offset = 2 ms + 0.5 ms + 1 ms = 3.5 ms
+ // 3.5 ms + 3 ms allocation = 6.5 ms > max of 5 ms
+ assertThrows(IllegalStateException.class, () -> robot.schedule(() -> {}, 0.003));
+
+ robot.endCompetition();
+ robot.close();
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/UltrasonicTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/UltrasonicTest.java
new file mode 100644
index 0000000..1b50572
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/UltrasonicTest.java
@@ -0,0 +1,31 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj;
+
+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.wpilibj.simulation.UltrasonicSim;
+import org.junit.jupiter.api.Test;
+
+public class UltrasonicTest {
+ @Test
+ public void testUltrasonic() {
+ try (Ultrasonic ultrasonic = new Ultrasonic(0, 1)) {
+ UltrasonicSim sim = new UltrasonicSim(ultrasonic);
+
+ assertEquals(0, ultrasonic.getRangeInches());
+ assertTrue(ultrasonic.isRangeValid());
+
+ sim.setRangeInches(35.04);
+ assertEquals(35.04, ultrasonic.getRangeInches());
+
+ sim.setRangeValid(false);
+ assertFalse(ultrasonic.isRangeValid());
+ assertEquals(0, ultrasonic.getRangeInches());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/UtilityClassTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/UtilityClassTest.java
index a66cd13..8eed93f 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/UtilityClassTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/UtilityClassTest.java
@@ -1,28 +1,30 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.stream.Stream;
-
-import org.junit.jupiter.api.DynamicTest;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestFactory;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestFactory;
+
+// Declaring this class abstract prevents UtilityClassTest from running on itself and throwing the
+// following exception:
+//
+// org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered
+// for parameter [java.lang.Class<T> arg0] in constructor [protected
+// edu.wpi.first.wpilibj.UtilityClassTest(java.lang.Class<T>)].
@SuppressWarnings("PMD.AbstractClassWithoutAbstractMethod")
public abstract class UtilityClassTest<T> {
private final Class<T> m_clazz;
@@ -33,8 +35,7 @@
@Test
public void singleConstructorTest() {
- assertEquals(1, m_clazz.getDeclaredConstructors().length,
- "More than one constructor defined");
+ assertEquals(1, m_clazz.getDeclaredConstructors().length, "More than one constructor defined");
}
@Test
@@ -55,7 +56,9 @@
Stream<DynamicTest> publicMethodsStaticTestFactory() {
return Arrays.stream(m_clazz.getDeclaredMethods())
.filter(method -> Modifier.isPublic(method.getModifiers()))
- .map(method -> dynamicTest(method.getName(),
- () -> assertTrue(Modifier.isStatic(method.getModifiers()))));
+ .map(
+ method ->
+ dynamicTest(
+ method.getName(), () -> assertTrue(Modifier.isStatic(method.getModifiers()))));
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/WatchdogTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/WatchdogTest.java
index d99d7db..c1676e0 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/WatchdogTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/WatchdogTest.java
@@ -1,26 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.parallel.ResourceLock;
-
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.simulation.SimHooks;
-
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.hal.HAL;
+import edu.wpi.first.wpilibj.simulation.SimHooks;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.ResourceLock;
+
class WatchdogTest {
@BeforeEach
void setup() {
@@ -38,9 +33,12 @@
void enableDisableTest() {
final AtomicInteger watchdogCounter = new AtomicInteger(0);
- try (Watchdog watchdog = new Watchdog(0.4, () -> {
- watchdogCounter.addAndGet(1);
- })) {
+ try (Watchdog watchdog =
+ new Watchdog(
+ 0.4,
+ () -> {
+ watchdogCounter.addAndGet(1);
+ })) {
// Run 1
watchdog.enable();
SimHooks.stepTiming(0.2);
@@ -54,8 +52,8 @@
SimHooks.stepTiming(0.4);
watchdog.disable();
- assertEquals(1, watchdogCounter.get(),
- "Watchdog either didn't trigger or triggered more than once");
+ assertEquals(
+ 1, watchdogCounter.get(), "Watchdog either didn't trigger or triggered more than once");
// Run 3
watchdogCounter.set(0);
@@ -63,8 +61,8 @@
SimHooks.stepTiming(1.0);
watchdog.disable();
- assertEquals(1, watchdogCounter.get(),
- "Watchdog either didn't trigger or triggered more than once");
+ assertEquals(
+ 1, watchdogCounter.get(), "Watchdog either didn't trigger or triggered more than once");
}
}
@@ -73,9 +71,12 @@
void resetTest() {
final AtomicInteger watchdogCounter = new AtomicInteger(0);
- try (Watchdog watchdog = new Watchdog(0.4, () -> {
- watchdogCounter.addAndGet(1);
- })) {
+ try (Watchdog watchdog =
+ new Watchdog(
+ 0.4,
+ () -> {
+ watchdogCounter.addAndGet(1);
+ })) {
watchdog.enable();
SimHooks.stepTiming(0.2);
watchdog.reset();
@@ -91,9 +92,12 @@
void setTimeoutTest() {
final AtomicInteger watchdogCounter = new AtomicInteger(0);
- try (Watchdog watchdog = new Watchdog(1.0, () -> {
- watchdogCounter.addAndGet(1);
- })) {
+ try (Watchdog watchdog =
+ new Watchdog(
+ 1.0,
+ () -> {
+ watchdogCounter.addAndGet(1);
+ })) {
watchdog.enable();
SimHooks.stepTiming(0.2);
watchdog.setTimeout(0.2);
@@ -104,16 +108,15 @@
SimHooks.stepTiming(0.3);
watchdog.disable();
- assertEquals(1, watchdogCounter.get(),
- "Watchdog either didn't trigger or triggered more than once");
+ assertEquals(
+ 1, watchdogCounter.get(), "Watchdog either didn't trigger or triggered more than once");
}
}
@Test
@ResourceLock("timing")
void isExpiredTest() {
- try (Watchdog watchdog = new Watchdog(0.2, () -> {
- })) {
+ try (Watchdog watchdog = new Watchdog(0.2, () -> {})) {
assertFalse(watchdog.isExpired());
watchdog.enable();
@@ -134,9 +137,12 @@
void epochsTest() {
final AtomicInteger watchdogCounter = new AtomicInteger(0);
- try (Watchdog watchdog = new Watchdog(0.4, () -> {
- watchdogCounter.addAndGet(1);
- })) {
+ try (Watchdog watchdog =
+ new Watchdog(
+ 0.4,
+ () -> {
+ watchdogCounter.addAndGet(1);
+ })) {
// Run 1
watchdog.enable();
watchdog.addEpoch("Epoch 1");
@@ -167,12 +173,18 @@
final AtomicInteger watchdogCounter1 = new AtomicInteger(0);
final AtomicInteger watchdogCounter2 = new AtomicInteger(0);
- try (Watchdog watchdog1 = new Watchdog(0.2, () -> {
- watchdogCounter1.addAndGet(1);
- });
- Watchdog watchdog2 = new Watchdog(0.6, () -> {
- watchdogCounter2.addAndGet(1);
- })) {
+ try (Watchdog watchdog1 =
+ new Watchdog(
+ 0.2,
+ () -> {
+ watchdogCounter1.addAndGet(1);
+ });
+ Watchdog watchdog2 =
+ new Watchdog(
+ 0.6,
+ () -> {
+ watchdogCounter2.addAndGet(1);
+ })) {
watchdog2.enable();
SimHooks.stepTiming(0.25);
assertEquals(0, watchdogCounter1.get(), "Watchdog triggered early");
@@ -184,8 +196,8 @@
watchdog1.disable();
watchdog2.disable();
- assertEquals(1, watchdogCounter1.get(),
- "Watchdog either didn't trigger or triggered more than once");
+ assertEquals(
+ 1, watchdogCounter1.get(), "Watchdog either didn't trigger or triggered more than once");
assertEquals(0, watchdogCounter2.get(), "Watchdog triggered early");
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/XboxControllerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/XboxControllerTest.java
index 34fce9a..d472377 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/XboxControllerTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/XboxControllerTest.java
@@ -1,86 +1,81 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj;
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.hal.HAL;
-import edu.wpi.first.wpilibj.simulation.XboxControllerSim;
-
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.hal.HAL;
+import edu.wpi.first.wpilibj.simulation.XboxControllerSim;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
class XboxControllerTest {
- @Test
- void testGetX() {
+ @ParameterizedTest
+ @EnumSource(value = XboxController.Button.class)
+ @SuppressWarnings({"VariableDeclarationUsageDistance"})
+ public void testButtons(XboxController.Button button)
+ throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
HAL.initialize(500, 0);
XboxController joy = new XboxController(2);
XboxControllerSim joysim = new XboxControllerSim(joy);
- joysim.setX(XboxController.Hand.kLeft, 0.35);
- joysim.setX(XboxController.Hand.kRight, 0.45);
+ var buttonName = button.toString();
+
+ String simSetMethodName = "set" + buttonName;
+ String joyGetMethodName = "get" + buttonName;
+ String joyPressedMethodName = "get" + buttonName + "Pressed";
+ String joyReleasedMethodName = "get" + buttonName + "Released";
+
+ Method simSetMethod = joysim.getClass().getMethod(simSetMethodName, boolean.class);
+ Method joyGetMethod = joy.getClass().getMethod(joyGetMethodName);
+ Method joyPressedMethod = joy.getClass().getMethod(joyPressedMethodName);
+ Method joyReleasedMethod = joy.getClass().getMethod(joyReleasedMethodName);
+
+ simSetMethod.invoke(joysim, false);
joysim.notifyNewData();
- assertEquals(0.35, joy.getX(XboxController.Hand.kLeft), 0.001);
- assertEquals(0.45, joy.getX(XboxController.Hand.kRight), 0.001);
+ assertFalse((Boolean) joyGetMethod.invoke(joy));
+ // need to call pressed and released to clear flags
+ joyPressedMethod.invoke(joy);
+ joyReleasedMethod.invoke(joy);
+
+ simSetMethod.invoke(joysim, true);
+ joysim.notifyNewData();
+ assertTrue((Boolean) joyGetMethod.invoke(joy));
+ assertTrue((Boolean) joyPressedMethod.invoke(joy));
+ assertFalse((Boolean) joyReleasedMethod.invoke(joy));
+
+ simSetMethod.invoke(joysim, false);
+ joysim.notifyNewData();
+ assertFalse((Boolean) joyGetMethod.invoke(joy));
+ assertFalse((Boolean) joyPressedMethod.invoke(joy));
+ assertTrue((Boolean) joyReleasedMethod.invoke(joy));
}
- @Test
- void testGetBumper() {
+ @ParameterizedTest
+ @EnumSource(value = XboxController.Axis.class)
+ @SuppressWarnings({"VariableDeclarationUsageDistance"})
+ public void testAxes(XboxController.Axis axis)
+ throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
HAL.initialize(500, 0);
XboxController joy = new XboxController(2);
XboxControllerSim joysim = new XboxControllerSim(joy);
- joysim.setBumper(XboxController.Hand.kLeft, false);
- joysim.setBumper(XboxController.Hand.kRight, true);
- joysim.notifyNewData();
- assertFalse(joy.getBumper(XboxController.Hand.kLeft));
- assertTrue(joy.getBumper(XboxController.Hand.kRight));
- // need to call pressed and released to clear flags
- joy.getBumperPressed(XboxController.Hand.kLeft);
- joy.getBumperReleased(XboxController.Hand.kLeft);
- joy.getBumperPressed(XboxController.Hand.kRight);
- joy.getBumperReleased(XboxController.Hand.kRight);
+ var axisName = axis.toString();
- joysim.setBumper(XboxController.Hand.kLeft, true);
- joysim.setBumper(XboxController.Hand.kRight, false);
- joysim.notifyNewData();
- assertTrue(joy.getBumper(XboxController.Hand.kLeft));
- assertTrue(joy.getBumperPressed(XboxController.Hand.kLeft));
- assertFalse(joy.getBumperReleased(XboxController.Hand.kLeft));
- assertFalse(joy.getBumper(XboxController.Hand.kRight));
- assertFalse(joy.getBumperPressed(XboxController.Hand.kRight));
- assertTrue(joy.getBumperReleased(XboxController.Hand.kRight));
- }
+ String simSetMethodName = "set" + axisName;
+ String joyGetMethodName = "get" + axisName;
- @Test
- void testGetAButton() {
- HAL.initialize(500, 0);
- XboxController joy = new XboxController(2);
- XboxControllerSim joysim = new XboxControllerSim(joy);
+ Method simSetMethod = joysim.getClass().getMethod(simSetMethodName, double.class);
+ Method joyGetMethod = joy.getClass().getMethod(joyGetMethodName);
- joysim.setAButton(false);
+ simSetMethod.invoke(joysim, 0.35);
joysim.notifyNewData();
- assertFalse(joy.getAButton());
- // need to call pressed and released to clear flags
- joy.getAButtonPressed();
- joy.getAButtonReleased();
-
- joysim.setAButton(true);
- joysim.notifyNewData();
- assertTrue(joy.getAButton());
- assertTrue(joy.getAButtonPressed());
- assertFalse(joy.getAButtonReleased());
-
- joysim.setAButton(false);
- joysim.notifyNewData();
- assertFalse(joy.getAButton());
- assertFalse(joy.getAButtonPressed());
- assertTrue(joy.getAButtonReleased());
+ assertEquals(0.35, (Double) joyGetMethod.invoke(joy), 0.001);
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/can/CANStatusTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/can/CANStatusTest.java
index e804d0c..71104fc 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/can/CANStatusTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/can/CANStatusTest.java
@@ -1,25 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.can;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.can.CANJNI;
import edu.wpi.first.hal.can.CANStatus;
-
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import org.junit.jupiter.api.Test;
class CANStatusTest {
@Test
void canStatusGetDoesntThrow() {
HAL.initialize(500, 0);
CANStatus status = new CANStatus();
- assertDoesNotThrow(() -> CANJNI.GetCANStatus(status));
+ assertDoesNotThrow(() -> CANJNI.getCANStatus(status));
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ControllerUtilTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ControllerUtilTest.java
deleted file mode 100644
index 307eccd..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ControllerUtilTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class ControllerUtilTest {
- @Test
- void testGetModulusError() {
- // Test symmetric range
- assertEquals(-20.0, ControllerUtil.getModulusError(170.0, -170.0, -180.0, 180.0));
- assertEquals(-20.0, ControllerUtil.getModulusError(170.0 + 360.0, -170.0, -180.0, 180.0));
- assertEquals(-20.0, ControllerUtil.getModulusError(170.0, -170.0 + 360.0, -180.0, 180.0));
- assertEquals(20.0, ControllerUtil.getModulusError(-170.0, 170.0, -180.0, 180.0));
- assertEquals(20.0, ControllerUtil.getModulusError(-170.0 + 360.0, 170.0, -180.0, 180.0));
- assertEquals(20.0, ControllerUtil.getModulusError(-170.0, 170.0 + 360.0, -180.0, 180.0));
-
- // Test range start at zero
- assertEquals(-20.0, ControllerUtil.getModulusError(170.0, 190.0, 0.0, 360.0));
- assertEquals(-20.0, ControllerUtil.getModulusError(170.0 + 360.0, 190.0, 0.0, 360.0));
- assertEquals(-20.0, ControllerUtil.getModulusError(170.0, 190.0 + 360, 0.0, 360.0));
-
- // Test asymmetric range that doesn't start at zero
- assertEquals(-20.0, ControllerUtil.getModulusError(170.0, -170.0, -170.0, 190.0));
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/HolonomicDriveControllerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/HolonomicDriveControllerTest.java
deleted file mode 100644
index 2bf7900..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/HolonomicDriveControllerTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.wpilibj.geometry.Pose2d;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
-import edu.wpi.first.wpilibj.geometry.Twist2d;
-import edu.wpi.first.wpilibj.kinematics.ChassisSpeeds;
-import edu.wpi.first.wpilibj.trajectory.Trajectory;
-import edu.wpi.first.wpilibj.trajectory.TrajectoryConfig;
-import edu.wpi.first.wpilibj.trajectory.TrajectoryGenerator;
-import edu.wpi.first.wpilibj.trajectory.TrapezoidProfile;
-import edu.wpi.first.wpiutil.math.MathUtil;
-
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class HolonomicDriveControllerTest {
- private static final double kTolerance = 1 / 12.0;
- private static final double kAngularTolerance = Math.toRadians(2);
-
- @Test
- @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
- void testReachesReference() {
- HolonomicDriveController controller = new HolonomicDriveController(
- new PIDController(1.0, 0.0, 0.0),
- new PIDController(1.0, 0.0, 0.0),
- new ProfiledPIDController(1.0, 0.0, 0.0,
- new TrapezoidProfile.Constraints(6.28, 3.14))
- );
- Pose2d robotPose = new Pose2d(2.7, 23.0, Rotation2d.fromDegrees(0.0));
-
- List<Pose2d> waypoints = new ArrayList<>();
- waypoints.add(new Pose2d(2.75, 22.521, new Rotation2d(0)));
- waypoints.add(new Pose2d(24.73, 19.68, new Rotation2d(5.8)));
-
- TrajectoryConfig config = new TrajectoryConfig(8.0, 4.0);
- Trajectory trajectory = TrajectoryGenerator.generateTrajectory(waypoints, config);
-
- final double kDt = 0.02;
- final double kTotalTime = trajectory.getTotalTimeSeconds();
-
- for (int i = 0; i < (kTotalTime / kDt); i++) {
- Trajectory.State state = trajectory.sample(kDt * i);
- ChassisSpeeds output = controller.calculate(robotPose, state, new Rotation2d());
-
- robotPose = robotPose.exp(new Twist2d(output.vxMetersPerSecond * kDt,
- output.vyMetersPerSecond * kDt, output.omegaRadiansPerSecond * kDt));
- }
-
- final List<Trajectory.State> states = trajectory.getStates();
- final Pose2d endPose = states.get(states.size() - 1).poseMeters;
-
- // Java lambdas require local variables referenced from a lambda expression
- // must be final or effectively final.
- final Pose2d finalRobotPose = robotPose;
-
- assertAll(
- () -> assertEquals(endPose.getX(), finalRobotPose.getX(),
- kTolerance),
- () -> assertEquals(endPose.getY(), finalRobotPose.getY(),
- kTolerance),
- () -> assertEquals(0.0,
- MathUtil.normalizeAngle(finalRobotPose.getRotation().getRadians()),
- kAngularTolerance)
- );
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/PIDInputOutputTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/PIDInputOutputTest.java
deleted file mode 100644
index 873d03f..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/PIDInputOutputTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-class PIDInputOutputTest {
- private PIDController m_controller;
-
- @BeforeEach
- void setUp() {
- m_controller = new PIDController(0, 0, 0);
- }
-
- @Test
- void continuousInputTest() {
- m_controller.setP(1);
- m_controller.enableContinuousInput(-180, 180);
-
- assertTrue(m_controller.calculate(-179, 179) < 0.0);
- }
-
- @Test
- void proportionalGainOutputTest() {
- m_controller.setP(4);
-
- assertEquals(-0.1, m_controller.calculate(0.025, 0), 1e-5);
- }
-
- @Test
- void integralGainOutputTest() {
- m_controller.setI(4);
-
- double out = 0;
-
- for (int i = 0; i < 5; i++) {
- out = m_controller.calculate(0.025, 0);
- }
-
- assertEquals(-0.5 * m_controller.getPeriod(), out, 1e-5);
- }
-
- @Test
- void derivativeGainOutputTest() {
- m_controller.setD(4);
-
- m_controller.calculate(0, 0);
-
- assertEquals(-0.01 / m_controller.getPeriod(), m_controller.calculate(0.0025, 0), 1e-5);
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/PIDToleranceTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/PIDToleranceTest.java
deleted file mode 100644
index b2d43c6..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/PIDToleranceTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-class PIDToleranceTest {
- private static final double kSetpoint = 50.0;
- private static final double kTolerance = 10.0;
- private static final double kRange = 200;
-
- @Test
- void initialToleranceTest() {
- try (var controller = new PIDController(0.05, 0.0, 0.0)) {
- controller.enableContinuousInput(-kRange / 2, kRange / 2);
-
- assertTrue(controller.atSetpoint());
- }
- }
-
- @Test
- void absoluteToleranceTest() {
- try (var controller = new PIDController(0.05, 0.0, 0.0)) {
- controller.enableContinuousInput(-kRange / 2, kRange / 2);
-
- controller.setTolerance(kTolerance);
- controller.setSetpoint(kSetpoint);
-
- controller.calculate(0.0);
-
- assertFalse(controller.atSetpoint(),
- "Error was in tolerance when it should not have been. Error was "
- + controller.getPositionError());
-
- controller.calculate(kSetpoint + kTolerance / 2);
-
- assertTrue(controller.atSetpoint(),
- "Error was not in tolerance when it should have been. Error was "
- + controller.getPositionError());
-
- controller.calculate(kSetpoint + 10 * kTolerance);
-
- assertFalse(controller.atSetpoint(),
- "Error was in tolerance when it should not have been. Error was "
- + controller.getPositionError());
- }
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ProfiledPIDControllerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ProfiledPIDControllerTest.java
deleted file mode 100644
index 6babcc2..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ProfiledPIDControllerTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.wpilibj.trajectory.TrapezoidProfile;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class ProfiledPIDControllerTest {
- @Test
- void testStartFromNonZeroPosition() {
- ProfiledPIDController controller = new ProfiledPIDController(1.0, 0.0, 0.0,
- new TrapezoidProfile.Constraints(1.0, 1.0));
-
- controller.reset(20);
-
- assertEquals(0.0, controller.calculate(20), 0.05);
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ProfiledPIDInputOutputTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ProfiledPIDInputOutputTest.java
deleted file mode 100644
index 9fca2a4..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/ProfiledPIDInputOutputTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.wpilibj.trajectory.TrapezoidProfile;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-class ProfiledPIDInputOutputTest {
- private ProfiledPIDController m_controller;
-
- @BeforeEach
- void setUp() {
- m_controller = new ProfiledPIDController(0, 0, 0,
- new TrapezoidProfile.Constraints(360, 180));
- }
-
- @Test
- void continuousInputTest1() {
- m_controller.setP(1);
- m_controller.enableContinuousInput(-180, 180);
-
- final double kSetpoint = -179.0;
- final double kMeasurement = -179.0;
- final double kGoal = 179.0;
-
- m_controller.reset(kSetpoint);
- assertTrue(m_controller.calculate(kMeasurement, kGoal) < 0.0);
-
- // Error must be less than half the input range at all times
- assertTrue(Math.abs(m_controller.getSetpoint().position - kMeasurement) < 180.0);
- }
-
- @Test
- void continuousInputTest2() {
- m_controller.setP(1);
- m_controller.enableContinuousInput(-Math.PI, Math.PI);
-
- final double kSetpoint = -3.4826633343199735;
- final double kMeasurement = -3.1352207333939606;
- final double kGoal = -3.534162788601621;
-
- m_controller.reset(kSetpoint);
- assertTrue(m_controller.calculate(kMeasurement, kGoal) < 0.0);
-
- // Error must be less than half the input range at all times
- assertTrue(Math.abs(m_controller.getSetpoint().position - kMeasurement) < Math.PI);
- }
-
- @Test
- void continuousInputTest3() {
- m_controller.setP(1);
- m_controller.enableContinuousInput(-Math.PI, Math.PI);
-
- final double kSetpoint = -3.5176604690006377;
- final double kMeasurement = 3.1191729343822456;
- final double kGoal = 2.709680418117445;
-
- m_controller.reset(kSetpoint);
- assertTrue(m_controller.calculate(kMeasurement, kGoal) < 0.0);
-
- // Error must be less than half the input range at all times
- assertTrue(Math.abs(m_controller.getSetpoint().position - kMeasurement) < Math.PI);
- }
-
- @Test
- void proportionalGainOutputTest() {
- m_controller.setP(4);
-
- assertEquals(-0.1, m_controller.calculate(0.025, 0), 1e-5);
- }
-
- @Test
- void integralGainOutputTest() {
- m_controller.setI(4);
-
- double out = 0;
-
- for (int i = 0; i < 5; i++) {
- out = m_controller.calculate(0.025, 0);
- }
-
- assertEquals(-0.5 * m_controller.getPeriod(), out, 1e-5);
- }
-
- @Test
- void derivativeGainOutputTest() {
- m_controller.setD(4);
-
- m_controller.calculate(0, 0);
-
- assertEquals(-0.01 / m_controller.getPeriod(), m_controller.calculate(0.0025, 0), 1e-5);
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/RamseteControllerTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/RamseteControllerTest.java
deleted file mode 100644
index a2b6e22..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/controller/RamseteControllerTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.controller;
-
-import java.util.ArrayList;
-
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.wpilibj.geometry.Pose2d;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
-import edu.wpi.first.wpilibj.geometry.Twist2d;
-import edu.wpi.first.wpilibj.trajectory.TrajectoryConfig;
-import edu.wpi.first.wpilibj.trajectory.TrajectoryGenerator;
-import edu.wpi.first.wpiutil.math.MathUtil;
-
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class RamseteControllerTest {
- private static final double kTolerance = 1 / 12.0;
- private static final double kAngularTolerance = Math.toRadians(2);
-
- @Test
- @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
- void testReachesReference() {
- final var controller = new RamseteController(2.0, 0.7);
- var robotPose = new Pose2d(2.7, 23.0, Rotation2d.fromDegrees(0.0));
-
- final var waypoints = new ArrayList<Pose2d>();
- waypoints.add(new Pose2d(2.75, 22.521, new Rotation2d(0)));
- waypoints.add(new Pose2d(24.73, 19.68, new Rotation2d(5.846)));
- var config = new TrajectoryConfig(8.8, 0.1);
- final var trajectory = TrajectoryGenerator.generateTrajectory(waypoints, config);
-
- final double kDt = 0.02;
- final var totalTime = trajectory.getTotalTimeSeconds();
- for (int i = 0; i < (totalTime / kDt); ++i) {
- var state = trajectory.sample(kDt * i);
-
- var output = controller.calculate(robotPose, state);
- robotPose = robotPose.exp(new Twist2d(output.vxMetersPerSecond * kDt, 0,
- output.omegaRadiansPerSecond * kDt));
- }
-
- final var states = trajectory.getStates();
- final var endPose = states.get(states.size() - 1).poseMeters;
-
- // Java lambdas require local variables referenced from a lambda expression
- // must be final or effectively final.
- final var finalRobotPose = robotPose;
- assertAll(
- () -> assertEquals(endPose.getX(), finalRobotPose.getX(),
- kTolerance),
- () -> assertEquals(endPose.getY(), finalRobotPose.getY(),
- kTolerance),
- () -> assertEquals(0.0,
- MathUtil.normalizeAngle(endPose.getRotation().getRadians()
- - finalRobotPose.getRotation().getRadians()),
- kAngularTolerance)
- );
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DifferentialDriveTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DifferentialDriveTest.java
new file mode 100644
index 0000000..e7f2e31
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DifferentialDriveTest.java
@@ -0,0 +1,240 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.drive;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.wpilibj.motorcontrol.MockMotorController;
+import org.junit.jupiter.api.Test;
+
+class DifferentialDriveTest {
+ @Test
+ void testArcadeDrive() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var drive = new DifferentialDrive(left, right);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.arcadeDrive(1.0, 0.0, false);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward left turn
+ drive.arcadeDrive(0.5, -0.5, false);
+ assertEquals(0.0, left.get(), 1e-9);
+ assertEquals(0.5, right.get(), 1e-9);
+
+ // Forward right turn
+ drive.arcadeDrive(0.5, 0.5, false);
+ assertEquals(0.5, left.get(), 1e-9);
+ assertEquals(0.0, right.get(), 1e-9);
+
+ // Backward
+ drive.arcadeDrive(-1.0, 0.0, false);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+
+ // Backward left turn
+ drive.arcadeDrive(-0.5, -0.5, false);
+ assertEquals(-0.5, left.get(), 1e-9);
+ assertEquals(0.0, right.get(), 1e-9);
+
+ // Backward right turn
+ drive.arcadeDrive(-0.5, 0.5, false);
+ assertEquals(0.0, left.get(), 1e-9);
+ assertEquals(-0.5, right.get(), 1e-9);
+ }
+
+ @Test
+ void testArcadeDriveSquared() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var drive = new DifferentialDrive(left, right);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.arcadeDrive(1.0, 0.0, true);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward left turn
+ drive.arcadeDrive(0.5, -0.5, true);
+ assertEquals(0.0, left.get(), 1e-9);
+ assertEquals(0.25, right.get(), 1e-9);
+
+ // Forward right turn
+ drive.arcadeDrive(0.5, 0.5, true);
+ assertEquals(0.25, left.get(), 1e-9);
+ assertEquals(0.0, right.get(), 1e-9);
+
+ // Backward
+ drive.arcadeDrive(-1.0, 0.0, true);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+
+ // Backward left turn
+ drive.arcadeDrive(-0.5, -0.5, true);
+ assertEquals(-0.25, left.get(), 1e-9);
+ assertEquals(0.0, right.get(), 1e-9);
+
+ // Backward right turn
+ drive.arcadeDrive(-0.5, 0.5, true);
+ assertEquals(0.0, left.get(), 1e-9);
+ assertEquals(-0.25, right.get(), 1e-9);
+ }
+
+ @Test
+ void testCurvatureDrive() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var drive = new DifferentialDrive(left, right);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.curvatureDrive(1.0, 0.0, false);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward left turn
+ drive.curvatureDrive(0.5, -0.5, false);
+ assertEquals(0.25, left.get(), 1e-9);
+ assertEquals(0.75, right.get(), 1e-9);
+
+ // Forward right turn
+ drive.curvatureDrive(0.5, 0.5, false);
+ assertEquals(0.75, left.get(), 1e-9);
+ assertEquals(0.25, right.get(), 1e-9);
+
+ // Backward
+ drive.curvatureDrive(-1.0, 0.0, false);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+
+ // Backward left turn
+ drive.curvatureDrive(-0.5, -0.5, false);
+ assertEquals(-0.75, left.get(), 1e-9);
+ assertEquals(-0.25, right.get(), 1e-9);
+
+ // Backward right turn
+ drive.curvatureDrive(-0.5, 0.5, false);
+ assertEquals(-0.25, left.get(), 1e-9);
+ assertEquals(-0.75, right.get(), 1e-9);
+ }
+
+ @Test
+ void testCurvatureDriveTurnInPlace() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var drive = new DifferentialDrive(left, right);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.curvatureDrive(1.0, 0.0, true);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward left turn
+ drive.curvatureDrive(0.5, -0.5, true);
+ assertEquals(0.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward right turn
+ drive.curvatureDrive(0.5, 0.5, true);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(0.0, right.get(), 1e-9);
+
+ // Backward
+ drive.curvatureDrive(-1.0, 0.0, true);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+
+ // Backward left turn
+ drive.curvatureDrive(-0.5, -0.5, true);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(0.0, right.get(), 1e-9);
+
+ // Backward right turn
+ drive.curvatureDrive(-0.5, 0.5, true);
+ assertEquals(0.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+ }
+
+ @Test
+ void testTankDrive() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var drive = new DifferentialDrive(left, right);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.tankDrive(1.0, 1.0, false);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward left turn
+ drive.tankDrive(0.5, 1.0, false);
+ assertEquals(0.5, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward right turn
+ drive.tankDrive(1.0, 0.5, false);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(0.5, right.get(), 1e-9);
+
+ // Backward
+ drive.tankDrive(-1.0, -1.0, false);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+
+ // Backward left turn
+ drive.tankDrive(-0.5, -1.0, false);
+ assertEquals(-0.5, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+
+ // Backward right turn
+ drive.tankDrive(-0.5, 1.0, false);
+ assertEquals(-0.5, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+ }
+
+ @Test
+ void testTankDriveSquared() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var drive = new DifferentialDrive(left, right);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.tankDrive(1.0, 1.0, true);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward left turn
+ drive.tankDrive(0.5, 1.0, true);
+ assertEquals(0.25, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+
+ // Forward right turn
+ drive.tankDrive(1.0, 0.5, true);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(0.25, right.get(), 1e-9);
+
+ // Backward
+ drive.tankDrive(-1.0, -1.0, true);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+
+ // Backward left turn
+ drive.tankDrive(-0.5, -1.0, true);
+ assertEquals(-0.25, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+
+ // Backward right turn
+ drive.tankDrive(-1.0, -0.5, true);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-0.25, right.get(), 1e-9);
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DriveTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DriveTest.java
deleted file mode 100644
index 14e9401..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DriveTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.drive;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.wpilibj.MockSpeedController;
-import edu.wpi.first.wpilibj.RobotDrive;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-/**
- * Tests DifferentialDrive and MecanumDrive.
- */
-public class DriveTest {
- private final MockSpeedController m_rdFrontLeft = new MockSpeedController();
- private final MockSpeedController m_rdRearLeft = new MockSpeedController();
- private final MockSpeedController m_rdFrontRight = new MockSpeedController();
- private final MockSpeedController m_rdRearRight = new MockSpeedController();
- private final MockSpeedController m_frontLeft = new MockSpeedController();
- private final MockSpeedController m_rearLeft = new MockSpeedController();
- private final MockSpeedController m_frontRight = new MockSpeedController();
- private final MockSpeedController m_rearRight = new MockSpeedController();
- private final RobotDrive m_robotDrive =
- new RobotDrive(m_rdFrontLeft, m_rdRearLeft, m_rdFrontRight, m_rdRearRight);
- private final DifferentialDrive m_differentialDrive =
- new DifferentialDrive(m_frontLeft, m_frontRight);
- private final MecanumDrive m_mecanumDrive =
- new MecanumDrive(m_frontLeft, m_rearLeft, m_frontRight, m_rearRight);
-
- private final double[] m_testJoystickValues = {1.0, 0.9, 0.5, 0.01, 0.0, -0.01, -0.5, -0.9,
- -1.0};
- private final double[] m_testGyroValues = {0, 30, 45, 90, 135, 180, 225, 270, 305, 360, 540,
- -45, -90, -135, -180, -225, -270, -305, -360, -540};
-
- @BeforeEach
- void setUp() {
- m_differentialDrive.setDeadband(0.0);
- m_differentialDrive.setSafetyEnabled(false);
- m_mecanumDrive.setDeadband(0.0);
- m_mecanumDrive.setSafetyEnabled(false);
- m_robotDrive.setSafetyEnabled(false);
- }
-
- @Test
- public void testTankDriveSquared() {
- for (double leftJoystick : m_testJoystickValues) {
- for (double rightJoystick : m_testJoystickValues) {
- m_robotDrive.tankDrive(leftJoystick, rightJoystick);
- m_differentialDrive.tankDrive(leftJoystick, rightJoystick);
- assertEquals(m_rdFrontLeft.get(), m_frontLeft.get(), 0.01,
- "Left Motor squared didn't match. Left Joystick: " + leftJoystick + " Right Joystick: "
- + rightJoystick);
- assertEquals(m_rdFrontRight.get(), m_frontRight.get(), 0.01,
- "Right Motor squared didn't match. Left Joystick: " + leftJoystick + " Right Joystick: "
- + rightJoystick);
- }
- }
- }
-
- @Test
- void testTankDrive() {
- for (double leftJoystick : m_testJoystickValues) {
- for (double rightJoystick : m_testJoystickValues) {
- m_robotDrive.tankDrive(leftJoystick, rightJoystick, false);
- m_differentialDrive.tankDrive(leftJoystick, rightJoystick, false);
- assertEquals(m_rdFrontLeft.get(), m_frontLeft.get(), 0.01,
- "Left Motor didn't match. Left Joystick: " + leftJoystick + " Right Joystick: "
- + rightJoystick);
- assertEquals(m_rdFrontRight.get(), m_frontRight.get(), 0.01,
- "Right Motor didn't match. Left Joystick: " + leftJoystick + " Right Joystick: "
- + rightJoystick);
- }
- }
- }
-
- @Test
- void testArcadeDriveSquared() {
- for (double moveJoystick : m_testJoystickValues) {
- for (double rotateJoystick : m_testJoystickValues) {
- m_robotDrive.arcadeDrive(moveJoystick, rotateJoystick);
- m_differentialDrive.arcadeDrive(moveJoystick, -rotateJoystick);
- assertEquals(m_rdFrontLeft.get(), m_frontLeft.get(), 0.01,
- "Left Motor squared didn't match. Move Joystick: " + moveJoystick + " Rotate Joystick: "
- + rotateJoystick);
- assertEquals(m_rdFrontRight.get(), m_frontRight.get(), 0.01,
- "Right Motor squared didn't match. Move Joystick: " + moveJoystick
- + " Rotate Joystick: " + rotateJoystick);
- }
- }
- }
-
- @Test
- void testArcadeDrive() {
- for (double moveJoystick : m_testJoystickValues) {
- for (double rotateJoystick : m_testJoystickValues) {
- m_robotDrive.arcadeDrive(moveJoystick, rotateJoystick, false);
- m_differentialDrive.arcadeDrive(moveJoystick, -rotateJoystick, false);
- assertEquals(m_rdFrontLeft.get(), m_frontLeft.get(), 0.01,
- "Left Motor didn't match. Move Joystick: " + moveJoystick + " Rotate Joystick: "
- + rotateJoystick);
- assertEquals(m_rdFrontRight.get(), m_frontRight.get(), 0.01,
- "Right Motor didn't match. Move Joystick: " + moveJoystick + " Rotate Joystick: "
- + rotateJoystick);
- }
- }
- }
-
- @Test
- void testMecanumPolar() {
- for (double magnitudeJoystick : m_testJoystickValues) {
- for (double directionJoystick : m_testGyroValues) {
- for (double rotationJoystick : m_testJoystickValues) {
- m_robotDrive.mecanumDrive_Polar(magnitudeJoystick, directionJoystick, rotationJoystick);
- m_mecanumDrive.drivePolar(magnitudeJoystick, directionJoystick, rotationJoystick);
- assertEquals(m_rdFrontLeft.get(), m_frontLeft.get(), 0.01,
- "Left Front Motor didn't match. Magnitude Joystick: " + magnitudeJoystick
- + " Direction Joystick: " + directionJoystick + " RotationJoystick: "
- + rotationJoystick);
- assertEquals(m_rdFrontRight.get(), -m_frontRight.get(), 0.01,
- "Right Front Motor didn't match. Magnitude Joystick: " + magnitudeJoystick
- + " Direction Joystick: " + directionJoystick + " RotationJoystick: "
- + rotationJoystick);
- assertEquals(m_rdRearLeft.get(), m_rearLeft.get(), 0.01,
- "Left Rear Motor didn't match. Magnitude Joystick: " + magnitudeJoystick
- + " Direction Joystick: " + directionJoystick + " RotationJoystick: "
- + rotationJoystick);
- assertEquals(m_rdRearRight.get(), -m_rearRight.get(), 0.01,
- "Right Rear Motor didn't match. Magnitude Joystick: " + magnitudeJoystick
- + " Direction Joystick: " + directionJoystick + " RotationJoystick: "
- + rotationJoystick);
- }
- }
- }
- }
-
- @Test
- @SuppressWarnings("checkstyle:LocalVariableName")
- void testMecanumCartesian() {
- for (double x_Joystick : m_testJoystickValues) {
- for (double y_Joystick : m_testJoystickValues) {
- for (double rotationJoystick : m_testJoystickValues) {
- for (double gyroValue : m_testGyroValues) {
- m_robotDrive.mecanumDrive_Cartesian(x_Joystick, y_Joystick, rotationJoystick,
- gyroValue);
- m_mecanumDrive.driveCartesian(x_Joystick, -y_Joystick, rotationJoystick, -gyroValue);
- assertEquals(m_rdFrontLeft.get(), m_frontLeft.get(), 0.01,
- "Left Front Motor didn't match. X Joystick: " + x_Joystick + " Y Joystick: "
- + y_Joystick + " RotationJoystick: " + rotationJoystick + " Gyro: " + gyroValue);
- assertEquals(m_rdFrontRight.get(), -m_frontRight.get(), 0.01,
- "Right Front Motor didn't match. X Joystick: " + x_Joystick + " Y Joystick: "
- + y_Joystick + " RotationJoystick: " + rotationJoystick + " Gyro: " + gyroValue);
- assertEquals(m_rdRearLeft.get(), m_rearLeft.get(), 0.01,
- "Left Rear Motor didn't match. X Joystick: " + x_Joystick + " Y Joystick: "
- + y_Joystick + " RotationJoystick: " + rotationJoystick + " Gyro: " + gyroValue);
- assertEquals(m_rdRearRight.get(), -m_rearRight.get(), 0.01,
- "Right Rear Motor didn't match. X Joystick: " + x_Joystick + " Y Joystick: "
- + y_Joystick + " RotationJoystick: " + rotationJoystick + " Gyro: " + gyroValue);
- }
- }
- }
- }
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/KilloughDriveTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/KilloughDriveTest.java
new file mode 100644
index 0000000..7d06d9f
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/KilloughDriveTest.java
@@ -0,0 +1,129 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.drive;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.wpilibj.motorcontrol.MockMotorController;
+import org.junit.jupiter.api.Test;
+
+class KilloughDriveTest {
+ @Test
+ void testCartesian() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var back = new MockMotorController();
+ var drive = new KilloughDrive(left, right, back);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.driveCartesian(1.0, 0.0, 0.0);
+ assertEquals(0.5, left.get(), 1e-9);
+ assertEquals(-0.5, right.get(), 1e-9);
+ assertEquals(0.0, back.get(), 1e-9);
+
+ // Left
+ drive.driveCartesian(0.0, -1.0, 0.0);
+ assertEquals(-Math.sqrt(3) / 2, left.get(), 1e-9);
+ assertEquals(-Math.sqrt(3) / 2, right.get(), 1e-9);
+ assertEquals(1.0, back.get(), 1e-9);
+
+ // Right
+ drive.driveCartesian(0.0, 1.0, 0.0);
+ assertEquals(Math.sqrt(3) / 2, left.get(), 1e-9);
+ assertEquals(Math.sqrt(3) / 2, right.get(), 1e-9);
+ assertEquals(-1.0, back.get(), 1e-9);
+
+ // Rotate CCW
+ drive.driveCartesian(0.0, 0.0, -1.0);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+ assertEquals(-1.0, back.get(), 1e-9);
+
+ // Rotate CW
+ drive.driveCartesian(0.0, 0.0, 1.0);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+ assertEquals(1.0, back.get(), 1e-9);
+ }
+
+ @Test
+ void testCartesiangyro90CW() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var back = new MockMotorController();
+ var drive = new KilloughDrive(left, right, back);
+ drive.setDeadband(0.0);
+
+ // Forward in global frame; left in robot frame
+ drive.driveCartesian(1.0, 0.0, 0.0, 90.0);
+ assertEquals(-Math.sqrt(3) / 2, left.get(), 1e-9);
+ assertEquals(-Math.sqrt(3) / 2, right.get(), 1e-9);
+ assertEquals(1.0, back.get(), 1e-9);
+
+ // Left in global frame; backward in robot frame
+ drive.driveCartesian(0.0, -1.0, 0.0, 90.0);
+ assertEquals(-0.5, left.get(), 1e-9);
+ assertEquals(0.5, right.get(), 1e-9);
+ assertEquals(0.0, back.get(), 1e-9);
+
+ // Right in global frame; forward in robot frame
+ drive.driveCartesian(0.0, 1.0, 0.0, 90.0);
+ assertEquals(0.5, left.get(), 1e-9);
+ assertEquals(-0.5, right.get(), 1e-9);
+ assertEquals(0.0, back.get(), 1e-9);
+
+ // Rotate CCW
+ drive.driveCartesian(0.0, 0.0, -1.0, 90.0);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+ assertEquals(-1.0, back.get(), 1e-9);
+
+ // Rotate CW
+ drive.driveCartesian(0.0, 0.0, 1.0, 90.0);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+ assertEquals(1.0, back.get(), 1e-9);
+ }
+
+ @Test
+ void testPolar() {
+ var left = new MockMotorController();
+ var right = new MockMotorController();
+ var back = new MockMotorController();
+ var drive = new KilloughDrive(left, right, back);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.drivePolar(1.0, 0.0, 0.0);
+ assertEquals(Math.sqrt(3) / 2, left.get(), 1e-9);
+ assertEquals(Math.sqrt(3) / 2, right.get(), 1e-9);
+ assertEquals(-1.0, back.get(), 1e-9);
+
+ // Left
+ drive.drivePolar(1.0, -90.0, 0.0);
+ assertEquals(-0.5, left.get(), 1e-9);
+ assertEquals(0.5, right.get(), 1e-9);
+ assertEquals(0.0, back.get(), 1e-9);
+
+ // Right
+ drive.drivePolar(1.0, 90.0, 0.0);
+ assertEquals(0.5, left.get(), 1e-9);
+ assertEquals(-0.5, right.get(), 1e-9);
+ assertEquals(0.0, back.get(), 1e-9);
+
+ // Rotate CCW
+ drive.drivePolar(0.0, 0.0, -1.0);
+ assertEquals(-1.0, left.get(), 1e-9);
+ assertEquals(-1.0, right.get(), 1e-9);
+ assertEquals(-1.0, back.get(), 1e-9);
+
+ // Rotate CW
+ drive.drivePolar(0.0, 0.0, 1.0);
+ assertEquals(1.0, left.get(), 1e-9);
+ assertEquals(1.0, right.get(), 1e-9);
+ assertEquals(1.0, back.get(), 1e-9);
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/MecanumDriveTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/MecanumDriveTest.java
new file mode 100644
index 0000000..70a07a2
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/MecanumDriveTest.java
@@ -0,0 +1,147 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.drive;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.wpilibj.motorcontrol.MockMotorController;
+import org.junit.jupiter.api.Test;
+
+class MecanumDriveTest {
+ @Test
+ void testCartesian() {
+ var fl = new MockMotorController();
+ var fr = new MockMotorController();
+ var rl = new MockMotorController();
+ var rr = new MockMotorController();
+ var drive = new MecanumDrive(fl, fr, rl, rr);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.driveCartesian(1.0, 0.0, 0.0);
+ assertEquals(1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(1.0, rr.get(), 1e-9);
+
+ // Left
+ drive.driveCartesian(0.0, -1.0, 0.0);
+ assertEquals(-1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(-1.0, rr.get(), 1e-9);
+
+ // Right
+ drive.driveCartesian(0.0, 1.0, 0.0);
+ assertEquals(1.0, fl.get(), 1e-9);
+ assertEquals(-1.0, fr.get(), 1e-9);
+ assertEquals(-1.0, rl.get(), 1e-9);
+ assertEquals(1.0, rr.get(), 1e-9);
+
+ // Rotate CCW
+ drive.driveCartesian(0.0, 0.0, -1.0);
+ assertEquals(-1.0, fl.get(), 1e-9);
+ assertEquals(-1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(1.0, rr.get(), 1e-9);
+
+ // Rotate CW
+ drive.driveCartesian(0.0, 0.0, 1.0);
+ assertEquals(1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(-1.0, rl.get(), 1e-9);
+ assertEquals(-1.0, rr.get(), 1e-9);
+ }
+
+ @Test
+ void testCartesiangyro90CW() {
+ var fl = new MockMotorController();
+ var fr = new MockMotorController();
+ var rl = new MockMotorController();
+ var rr = new MockMotorController();
+ var drive = new MecanumDrive(fl, fr, rl, rr);
+ drive.setDeadband(0.0);
+
+ // Forward in global frame; left in robot frame
+ drive.driveCartesian(1.0, 0.0, 0.0, 90.0);
+ assertEquals(-1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(-1.0, rr.get(), 1e-9);
+
+ // Left in global frame; backward in robot frame
+ drive.driveCartesian(0.0, -1.0, 0.0, 90.0);
+ assertEquals(-1.0, fl.get(), 1e-9);
+ assertEquals(-1.0, fr.get(), 1e-9);
+ assertEquals(-1.0, rl.get(), 1e-9);
+ assertEquals(-1.0, rr.get(), 1e-9);
+
+ // Right in global frame; forward in robot frame
+ drive.driveCartesian(0.0, 1.0, 0.0, 90.0);
+ assertEquals(1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(1.0, rr.get(), 1e-9);
+
+ // Rotate CCW
+ drive.driveCartesian(0.0, 0.0, -1.0, 90.0);
+ assertEquals(-1.0, fl.get(), 1e-9);
+ assertEquals(-1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(1.0, rr.get(), 1e-9);
+
+ // Rotate CW
+ drive.driveCartesian(0.0, 0.0, 1.0, 90.0);
+ assertEquals(1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(-1.0, rl.get(), 1e-9);
+ assertEquals(-1.0, rr.get(), 1e-9);
+ }
+
+ @Test
+ void testPolar() {
+ var fl = new MockMotorController();
+ var fr = new MockMotorController();
+ var rl = new MockMotorController();
+ var rr = new MockMotorController();
+ var drive = new MecanumDrive(fl, fr, rl, rr);
+ drive.setDeadband(0.0);
+
+ // Forward
+ drive.drivePolar(1.0, 0.0, 0.0);
+ assertEquals(1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(1.0, rr.get(), 1e-9);
+
+ // Left
+ drive.drivePolar(1.0, -90.0, 0.0);
+ assertEquals(-1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(-1.0, rr.get(), 1e-9);
+
+ // Right
+ drive.drivePolar(1.0, 90.0, 0.0);
+ assertEquals(1.0, fl.get(), 1e-9);
+ assertEquals(-1.0, fr.get(), 1e-9);
+ assertEquals(-1.0, rl.get(), 1e-9);
+ assertEquals(1.0, rr.get(), 1e-9);
+
+ // Rotate CCW
+ drive.drivePolar(0.0, 0.0, -1.0);
+ assertEquals(-1.0, fl.get(), 1e-9);
+ assertEquals(-1.0, fr.get(), 1e-9);
+ assertEquals(1.0, rl.get(), 1e-9);
+ assertEquals(1.0, rr.get(), 1e-9);
+
+ // Rotate CW
+ drive.drivePolar(0.0, 0.0, 1.0);
+ assertEquals(1.0, fl.get(), 1e-9);
+ assertEquals(1.0, fr.get(), 1e-9);
+ assertEquals(-1.0, rl.get(), 1e-9);
+ assertEquals(-1.0, rr.get(), 1e-9);
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/JNITest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/JNITest.java
index f70f3f8..083e82c 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/JNITest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/JNITest.java
@@ -1,17 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.hal;
-import org.junit.jupiter.api.Test;
-
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.HALUtil;
import edu.wpi.first.networktables.NetworkTablesJNI;
+import org.junit.jupiter.api.Test;
class JNITest {
@Test
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/MatchInfoDataTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/MatchInfoDataTest.java
index 3887d91..855ace5 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/MatchInfoDataTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/hal/MatchInfoDataTest.java
@@ -1,26 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.hal;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.hal.MatchInfoData;
import edu.wpi.first.hal.simulation.DriverStationDataJNI;
import edu.wpi.first.wpilibj.DriverStation.MatchType;
-
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
class MatchInfoDataTest {
@Test
void testSetMatchInfo() {
-
MatchType matchType = MatchType.Qualification;
DriverStationDataJNI.setMatchInfo("Event Name", "Game Message", 174, 191, matchType.ordinal());
@@ -32,7 +27,6 @@
() -> assertEquals(matchType.ordinal(), outMatchInfo.matchType),
() -> assertEquals(174, outMatchInfo.matchNumber),
() -> assertEquals(191, outMatchInfo.replayNumber),
- () -> assertEquals("Game Message", outMatchInfo.gameSpecificMessage)
- );
+ () -> assertEquals("Game Message", outMatchInfo.gameSpecificMessage));
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/livewindow/LiveWindowTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/livewindow/LiveWindowTest.java
index dd33945..6d4a666 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/livewindow/LiveWindowTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/livewindow/LiveWindowTest.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.livewindow;
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/motorcontrol/MockMotorController.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/motorcontrol/MockMotorController.java
new file mode 100644
index 0000000..e7a6b8e
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/motorcontrol/MockMotorController.java
@@ -0,0 +1,40 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+public class MockMotorController implements MotorController {
+ private double m_speed;
+ private boolean m_isInverted;
+
+ @Override
+ public void set(double speed) {
+ m_speed = m_isInverted ? -speed : speed;
+ }
+
+ @Override
+ public double get() {
+ return m_speed;
+ }
+
+ @Override
+ public void setInverted(boolean isInverted) {
+ m_isInverted = isInverted;
+ }
+
+ @Override
+ public boolean getInverted() {
+ return m_isInverted;
+ }
+
+ @Override
+ public void disable() {
+ m_speed = 0;
+ }
+
+ @Override
+ public void stopMotor() {
+ disable();
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/motorcontrol/MotorControllerGroupTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/motorcontrol/MotorControllerGroupTest.java
new file mode 100644
index 0000000..6efb3de
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/motorcontrol/MotorControllerGroupTest.java
@@ -0,0 +1,101 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.motorcontrol;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class MotorControllerGroupTest {
+ private static Stream<Arguments> motorControllerArguments() {
+ return IntStream.of(1, 2, 3)
+ .mapToObj(
+ number -> {
+ MotorController[] motorControllers =
+ Stream.generate(MockMotorController::new)
+ .limit(number)
+ .toArray(MotorController[]::new);
+ MotorControllerGroup group =
+ new MotorControllerGroup(
+ motorControllers[0],
+ Arrays.copyOfRange(motorControllers, 1, motorControllers.length));
+ return Arguments.of(group, motorControllers);
+ });
+ }
+
+ @ParameterizedTest
+ @MethodSource("motorControllerArguments")
+ void setTest(final MotorControllerGroup group, final MotorController[] motorControllers) {
+ group.set(1.0);
+
+ assertArrayEquals(
+ DoubleStream.generate(() -> 1.0).limit(motorControllers.length).toArray(),
+ Arrays.stream(motorControllers).mapToDouble(MotorController::get).toArray(),
+ 0.00005);
+ }
+
+ @ParameterizedTest
+ @MethodSource("motorControllerArguments")
+ void getInvertedTest(final MotorControllerGroup group, final MotorController[] motorControllers) {
+ group.setInverted(true);
+
+ assertTrue(group.getInverted());
+ }
+
+ @ParameterizedTest
+ @MethodSource("motorControllerArguments")
+ void setInvertedDoesNotModifyMotorControllersTest(
+ final MotorControllerGroup group, final MotorController[] motorControllers) {
+ group.setInverted(true);
+
+ assertArrayEquals(
+ Stream.generate(() -> false).limit(motorControllers.length).toArray(),
+ Arrays.stream(motorControllers).map(MotorController::getInverted).toArray());
+ }
+
+ @ParameterizedTest
+ @MethodSource("motorControllerArguments")
+ void setInvertedDoesInvertTest(
+ final MotorControllerGroup group, final MotorController[] motorControllers) {
+ group.setInverted(true);
+ group.set(1.0);
+
+ assertArrayEquals(
+ DoubleStream.generate(() -> -1.0).limit(motorControllers.length).toArray(),
+ Arrays.stream(motorControllers).mapToDouble(MotorController::get).toArray(),
+ 0.00005);
+ }
+
+ @ParameterizedTest
+ @MethodSource("motorControllerArguments")
+ void disableTest(final MotorControllerGroup group, final MotorController[] motorControllers) {
+ group.set(1.0);
+ group.disable();
+
+ assertArrayEquals(
+ DoubleStream.generate(() -> 0.0).limit(motorControllers.length).toArray(),
+ Arrays.stream(motorControllers).mapToDouble(MotorController::get).toArray(),
+ 0.00005);
+ }
+
+ @ParameterizedTest
+ @MethodSource("motorControllerArguments")
+ void stopMotorTest(final MotorControllerGroup group, final MotorController[] motorControllers) {
+ group.set(1.0);
+ group.stopMotor();
+
+ assertArrayEquals(
+ DoubleStream.generate(() -> 0.0).limit(motorControllers.length).toArray(),
+ Arrays.stream(motorControllers).mapToDouble(MotorController::get).toArray(),
+ 0.00005);
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/MockActuatorSendable.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/MockActuatorSendable.java
index 89ca3ec..04397c2 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/MockActuatorSendable.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/MockActuatorSendable.java
@@ -1,19 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
-import edu.wpi.first.wpilibj.Sendable;
-import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
-import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
-/**
- * A mock sendable that marks itself as an actuator.
- */
+/** A mock sendable that marks itself as an actuator. */
public class MockActuatorSendable implements Sendable {
public MockActuatorSendable(String name) {
SendableRegistry.add(this, name);
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstanceTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstanceTest.java
index 9824f11..61db14a 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstanceTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardInstanceTest.java
@@ -1,24 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.networktables.NetworkTableEntry;
-import edu.wpi.first.networktables.NetworkTableInstance;
-
import static org.junit.jupiter.api.Assertions.assertAll;
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.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
public class ShuffleboardInstanceTest {
private NetworkTableInstance m_ntInstance;
private ShuffleboardInstance m_shuffleboardInstance;
@@ -36,32 +32,42 @@
@Test
void testPathFluent() {
- NetworkTableEntry entry = m_shuffleboardInstance.getTab("Tab Title")
- .getLayout("Layout Title", "List Layout")
- .add("Data", "string")
- .withWidget("Text View")
- .getEntry();
+ NetworkTableEntry entry =
+ m_shuffleboardInstance
+ .getTab("Tab Title")
+ .getLayout("Layout Title", "List Layout")
+ .add("Data", "string")
+ .withWidget("Text View")
+ .getEntry();
assertAll(
() -> assertEquals("string", entry.getString(null), "Wrong entry value"),
- () -> assertEquals("/Shuffleboard/Tab Title/Layout Title/Data", entry.getName(),
- "Entry path generated incorrectly"));
+ () ->
+ assertEquals(
+ "/Shuffleboard/Tab Title/Layout Title/Data",
+ entry.getName(),
+ "Entry path generated incorrectly"));
}
@Test
void testNestedLayoutsFluent() {
- NetworkTableEntry entry = m_shuffleboardInstance.getTab("Tab")
- .getLayout("First", "List")
- .getLayout("Second", "List")
- .getLayout("Third", "List")
- .getLayout("Fourth", "List")
- .add("Value", "string")
- .getEntry();
+ NetworkTableEntry entry =
+ m_shuffleboardInstance
+ .getTab("Tab")
+ .getLayout("First", "List")
+ .getLayout("Second", "List")
+ .getLayout("Third", "List")
+ .getLayout("Fourth", "List")
+ .add("Value", "string")
+ .getEntry();
assertAll(
() -> assertEquals("string", entry.getString(null), "Wrong entry value"),
- () -> assertEquals("/Shuffleboard/Tab/First/Second/Third/Fourth/Value", entry.getName(),
- "Entry path generated incorrectly"));
+ () ->
+ assertEquals(
+ "/Shuffleboard/Tab/First/Second/Third/Fourth/Value",
+ entry.getName(),
+ "Entry path generated incorrectly"));
}
@Test
@@ -76,26 +82,29 @@
assertAll(
() -> assertEquals("string", entry.getString(null), "Wrong entry value"),
- () -> assertEquals("/Shuffleboard/Tab/First/Second/Third/Fourth/Value", entry.getName(),
- "Entry path generated incorrectly"));
+ () ->
+ assertEquals(
+ "/Shuffleboard/Tab/First/Second/Third/Fourth/Value",
+ entry.getName(),
+ "Entry path generated incorrectly"));
}
@Test
void testLayoutTypeIsSet() {
String layoutType = "Type";
- m_shuffleboardInstance.getTab("Tab")
- .getLayout("Title", layoutType);
+ m_shuffleboardInstance.getTab("Tab").getLayout("Title", layoutType);
m_shuffleboardInstance.update();
- NetworkTableEntry entry = m_ntInstance.getEntry(
- "/Shuffleboard/.metadata/Tab/Title/PreferredComponent");
+ NetworkTableEntry entry =
+ m_ntInstance.getEntry("/Shuffleboard/.metadata/Tab/Title/PreferredComponent");
assertEquals(layoutType, entry.getString("Not Set"), "Layout type not set");
}
@Test
void testNestedActuatorWidgetsAreDisabled() {
- m_shuffleboardInstance.getTab("Tab")
- .getLayout("Title", "Layout")
- .add(new MockActuatorSendable("Actuator"));
+ m_shuffleboardInstance
+ .getTab("Tab")
+ .getLayout("Title", "Layout")
+ .add(new MockActuatorSendable("Actuator"));
NetworkTableEntry controllableEntry =
m_ntInstance.getEntry("/Shuffleboard/Tab/Title/Actuator/.controllable");
@@ -111,5 +120,4 @@
controllable = controllableEntry.getValue().getBoolean();
assertFalse(controllable, "The nested actuator widget should have been disabled");
}
-
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardTest.java
index 1469170..963d262 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/ShuffleboardTest.java
@@ -1,17 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertSame;
import edu.wpi.first.wpilibj.UtilityClassTest;
-
-import static org.junit.jupiter.api.Assertions.assertSame;
+import org.junit.jupiter.api.Test;
public class ShuffleboardTest extends UtilityClassTest<Shuffleboard> {
public ShuffleboardTest() {
@@ -26,5 +22,4 @@
ShuffleboardTab tab2 = Shuffleboard.getTab("testTabObjectsCached");
assertSame(tab1, tab2, "Tab objects were not cached");
}
-
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/SuppliedValueWidgetTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/SuppliedValueWidgetTest.java
index 6e0da8e..036c73d 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/SuppliedValueWidgetTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/shuffleboard/SuppliedValueWidgetTest.java
@@ -1,25 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.shuffleboard;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.networktables.NetworkTableEntry;
-import edu.wpi.first.networktables.NetworkTableInstance;
-
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
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.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
class SuppliedValueWidgetTest {
private NetworkTableInstance m_ntInstance;
private ShuffleboardInstance m_instance;
@@ -33,8 +28,7 @@
@Test
void testAddString() {
AtomicInteger count = new AtomicInteger(0);
- m_instance.getTab("Tab")
- .addString("Title", () -> Integer.toString(count.incrementAndGet()));
+ m_instance.getTab("Tab").addString("Title", () -> Integer.toString(count.incrementAndGet()));
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
m_instance.update();
@@ -47,8 +41,7 @@
@Test
void testAddDouble() {
AtomicInteger num = new AtomicInteger(0);
- m_instance.getTab("Tab")
- .addNumber("Title", num::incrementAndGet);
+ m_instance.getTab("Tab").addNumber("Title", num::incrementAndGet);
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
m_instance.update();
@@ -61,8 +54,7 @@
@Test
void testAddBoolean() {
boolean[] bool = {false};
- m_instance.getTab("Tab")
- .addBoolean("Title", () -> bool[0] = !bool[0]);
+ m_instance.getTab("Tab").addBoolean("Title", () -> bool[0] = !bool[0]);
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
m_instance.update();
@@ -75,8 +67,7 @@
@Test
void testAddStringArray() {
String[] arr = {"foo", "bar"};
- m_instance.getTab("Tab")
- .addStringArray("Title", () -> arr);
+ m_instance.getTab("Tab").addStringArray("Title", () -> arr);
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
m_instance.update();
@@ -86,8 +77,7 @@
@Test
void testAddDoubleArray() {
double[] arr = {0, 1};
- m_instance.getTab("Tab")
- .addDoubleArray("Title", () -> arr);
+ m_instance.getTab("Tab").addDoubleArray("Title", () -> arr);
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
m_instance.update();
@@ -97,8 +87,7 @@
@Test
void testAddBooleanArray() {
boolean[] arr = {true, false};
- m_instance.getTab("Tab")
- .addBooleanArray("Title", () -> arr);
+ m_instance.getTab("Tab").addBooleanArray("Title", () -> arr);
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
m_instance.update();
@@ -108,12 +97,10 @@
@Test
void testAddRawBytes() {
byte[] arr = {0, 1, 2, 3};
- m_instance.getTab("Tab")
- .addRaw("Title", () -> arr);
+ m_instance.getTab("Tab").addRaw("Title", () -> arr);
NetworkTableEntry entry = m_ntInstance.getEntry("/Shuffleboard/Tab/Title");
m_instance.update();
assertArrayEquals(arr, entry.getRaw(new byte[0]));
}
-
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL345SimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL345SimTest.java
new file mode 100644
index 0000000..7f41038
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL345SimTest.java
@@ -0,0 +1,64 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.ADXL345_I2C;
+import edu.wpi.first.wpilibj.ADXL345_SPI;
+import edu.wpi.first.wpilibj.I2C;
+import edu.wpi.first.wpilibj.SPI;
+import edu.wpi.first.wpilibj.interfaces.Accelerometer;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+public class ADXL345SimTest {
+ @ParameterizedTest
+ @EnumSource(Accelerometer.Range.class)
+ void testInitI2C(Accelerometer.Range range) {
+ HAL.initialize(500, 0);
+
+ try (ADXL345_I2C accel = new ADXL345_I2C(I2C.Port.kMXP, range)) {
+ ADXL345Sim sim = new ADXL345Sim(accel);
+
+ sim.setX(1.91);
+ sim.setY(-3.405);
+ sim.setZ(2.29);
+
+ assertEquals(1.91, accel.getX());
+ assertEquals(-3.405, accel.getY());
+ assertEquals(2.29, accel.getZ());
+
+ ADXL345_I2C.AllAxes allAccel = accel.getAccelerations();
+ assertEquals(1.91, allAccel.XAxis);
+ assertEquals(-3.405, allAccel.YAxis);
+ assertEquals(2.29, allAccel.ZAxis);
+ }
+ }
+
+ @ParameterizedTest
+ @EnumSource(Accelerometer.Range.class)
+ void testInitSPi(Accelerometer.Range range) {
+ HAL.initialize(500, 0);
+
+ try (ADXL345_SPI accel = new ADXL345_SPI(SPI.Port.kMXP, range)) {
+ ADXL345Sim sim = new ADXL345Sim(accel);
+
+ sim.setX(1.91);
+ sim.setY(-3.405);
+ sim.setZ(2.29);
+
+ assertEquals(1.91, accel.getX());
+ assertEquals(-3.405, accel.getY());
+ assertEquals(2.29, accel.getZ());
+
+ ADXL345_SPI.AllAxes allAccel = accel.getAccelerations();
+ assertEquals(1.91, allAccel.XAxis);
+ assertEquals(-3.405, allAccel.YAxis);
+ assertEquals(2.29, allAccel.ZAxis);
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL362SimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL362SimTest.java
new file mode 100644
index 0000000..f361381
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXL362SimTest.java
@@ -0,0 +1,42 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.ADXL362;
+import edu.wpi.first.wpilibj.SPI;
+import edu.wpi.first.wpilibj.interfaces.Accelerometer;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+public class ADXL362SimTest {
+ @ParameterizedTest
+ @EnumSource(Accelerometer.Range.class)
+ void testAccel(Accelerometer.Range range) {
+ HAL.initialize(500, 0);
+
+ try (ADXL362 accel = new ADXL362(SPI.Port.kMXP, range)) {
+ assertEquals(0, accel.getX());
+ assertEquals(0, accel.getY());
+ assertEquals(0, accel.getZ());
+
+ ADXL362Sim sim = new ADXL362Sim(accel);
+ sim.setX(1.91);
+ sim.setY(-3.405);
+ sim.setZ(2.29);
+
+ assertEquals(1.91, accel.getX());
+ assertEquals(-3.405, accel.getY());
+ assertEquals(2.29, accel.getZ());
+
+ ADXL362.AllAxes allAccel = accel.getAccelerations();
+ assertEquals(1.91, allAccel.XAxis);
+ assertEquals(-3.405, allAccel.YAxis);
+ assertEquals(2.29, allAccel.ZAxis);
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXRS450_GyroSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXRS450_GyroSimTest.java
new file mode 100644
index 0000000..301cef1
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ADXRS450_GyroSimTest.java
@@ -0,0 +1,35 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.ADXRS450_Gyro;
+import org.junit.jupiter.api.Test;
+
+@SuppressWarnings({"TypeName"})
+class ADXRS450_GyroSimTest {
+ @Test
+ void testCallbacks() {
+ HAL.initialize(500, 0);
+
+ try (ADXRS450_Gyro gyro = new ADXRS450_Gyro()) {
+ ADXRS450_GyroSim sim = new ADXRS450_GyroSim(gyro);
+
+ assertEquals(0, gyro.getAngle());
+ assertEquals(0, gyro.getRate());
+
+ sim.setAngle(123.456);
+ sim.setRate(229.3504);
+
+ assertEquals(123.456, gyro.getAngle());
+ assertEquals(229.3504, gyro.getRate());
+
+ gyro.reset();
+ assertEquals(0, gyro.getAngle());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AccelerometerSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AccelerometerSimTest.java
index 05ea290..998b66a 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AccelerometerSimTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AccelerometerSimTest.java
@@ -1,42 +1,142 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.hal.AccelerometerJNI;
-import edu.wpi.first.hal.HAL;
-
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-class AccelerometerSimTest {
- static class TriggeredStore {
- public boolean m_wasTriggered;
- public boolean m_setValue = true;
- }
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.BuiltInAccelerometer;
+import edu.wpi.first.wpilibj.interfaces.Accelerometer;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.EnumCallback;
+import org.junit.jupiter.api.Test;
+class AccelerometerSimTest {
@Test
void testCallbacks() {
HAL.initialize(500, 0);
BuiltInAccelerometerSim sim = new BuiltInAccelerometerSim();
sim.resetData();
- TriggeredStore store = new TriggeredStore();
+ BooleanCallback store = new BooleanCallback();
- try (CallbackStore cb = sim.registerActiveCallback((s, v) -> {
- store.m_wasTriggered = true;
- store.m_setValue = v.getBoolean();
- }, false)) {
- assertFalse(store.m_wasTriggered);
- AccelerometerJNI.setAccelerometerActive(true);
- assertTrue(store.m_wasTriggered);
- assertTrue(store.m_setValue);
+ try (CallbackStore cb = sim.registerActiveCallback(store, false)) {
+ assertFalse(store.wasTriggered());
+ sim.setActive(true);
+ assertTrue(sim.getActive());
+ assertTrue(store.wasTriggered());
+ assertTrue(store.getSetValue());
+ }
+ }
+
+ @Test
+ void testX() {
+ HAL.initialize(500, 0);
+ BuiltInAccelerometerSim sim = new BuiltInAccelerometerSim();
+ sim.resetData();
+
+ DoubleCallback callback = new DoubleCallback();
+ final double kTestValue = 1.91;
+
+ try (BuiltInAccelerometer accel = new BuiltInAccelerometer();
+ CallbackStore cb = sim.registerXCallback(callback, false)) {
+ sim.setX(kTestValue);
+ assertEquals(kTestValue, accel.getX());
+ assertEquals(kTestValue, sim.getX());
+ assertTrue(callback.wasTriggered());
+ assertEquals(kTestValue, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testY() {
+ HAL.initialize(500, 0);
+ BuiltInAccelerometerSim sim = new BuiltInAccelerometerSim();
+ sim.resetData();
+
+ DoubleCallback callback = new DoubleCallback();
+ final double kTestValue = 2.29;
+
+ try (BuiltInAccelerometer accel = new BuiltInAccelerometer();
+ CallbackStore cb = sim.registerYCallback(callback, false)) {
+ sim.setY(kTestValue);
+ assertEquals(kTestValue, accel.getY());
+ assertEquals(kTestValue, sim.getY());
+ assertTrue(callback.wasTriggered());
+ assertEquals(kTestValue, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testZ() {
+ HAL.initialize(500, 0);
+
+ BuiltInAccelerometerSim sim = new BuiltInAccelerometerSim();
+ sim.resetData();
+
+ DoubleCallback callback = new DoubleCallback();
+ final double kTestValue = 3.405;
+
+ try (BuiltInAccelerometer accel = new BuiltInAccelerometer();
+ CallbackStore cb = sim.registerZCallback(callback, false)) {
+ sim.setZ(kTestValue);
+ assertEquals(kTestValue, accel.getZ());
+ assertEquals(kTestValue, sim.getZ());
+ assertTrue(callback.wasTriggered());
+ assertEquals(kTestValue, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testRange() {
+ HAL.initialize(500, 0);
+
+ BuiltInAccelerometerSim sim = new BuiltInAccelerometerSim();
+ sim.resetData();
+
+ EnumCallback callback = new EnumCallback();
+
+ Accelerometer.Range range = Accelerometer.Range.k4G;
+ try (CallbackStore cb = sim.registerRangeCallback(callback, false);
+ BuiltInAccelerometer accel = new BuiltInAccelerometer(range)) {
+ assertTrue(callback.wasTriggered());
+ assertEquals(range.ordinal(), sim.getRange());
+ assertEquals(range.ordinal(), callback.getSetValue());
+
+ // 2G
+ callback.reset();
+ range = Accelerometer.Range.k2G;
+ accel.setRange(range);
+ assertTrue(callback.wasTriggered());
+ assertEquals(range.ordinal(), sim.getRange());
+ assertEquals(range.ordinal(), callback.getSetValue());
+
+ // 4G
+ callback.reset();
+ range = Accelerometer.Range.k4G;
+ accel.setRange(range);
+ assertTrue(callback.wasTriggered());
+ assertEquals(range.ordinal(), sim.getRange());
+ assertEquals(range.ordinal(), callback.getSetValue());
+
+ // 8G
+ callback.reset();
+ range = Accelerometer.Range.k8G;
+ accel.setRange(range);
+ assertTrue(callback.wasTriggered());
+ assertEquals(range.ordinal(), sim.getRange());
+ assertEquals(range.ordinal(), callback.getSetValue());
+
+ // 16G - Not supported
+ callback.reset();
+ assertThrows(IllegalArgumentException.class, () -> accel.setRange(Accelerometer.Range.k16G));
+ assertFalse(callback.wasTriggered());
}
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSimTest.java
new file mode 100644
index 0000000..096f77e
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AddressableLEDSimTest.java
@@ -0,0 +1,133 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.hal.HAL;
+import edu.wpi.first.wpilibj.AddressableLED;
+import edu.wpi.first.wpilibj.AddressableLEDBuffer;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.BufferCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.IntCallback;
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+
+class AddressableLEDSimTest {
+ @Test
+ void testInitialization() {
+ HAL.initialize(500, 0);
+ AddressableLEDSim sim = new AddressableLEDSim();
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback initializedCallback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerInitializedCallback(initializedCallback, false);
+ AddressableLED led = new AddressableLED(0)) {
+ assertTrue(sim.getInitialized());
+ assertTrue(initializedCallback.wasTriggered());
+ assertTrue(initializedCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testLength() {
+ AddressableLEDSim sim = new AddressableLEDSim();
+ IntCallback callback = new IntCallback();
+ try (CallbackStore cb = sim.registerLengthCallback(callback, false);
+ AddressableLED led = new AddressableLED(0)) {
+ assertEquals(1, sim.getLength()); // Defaults to 1 led
+
+ AddressableLEDBuffer ledData = new AddressableLEDBuffer(50);
+ led.setLength(ledData.getLength());
+ led.setData(ledData);
+
+ assertEquals(50, sim.getLength());
+ assertTrue(callback.wasTriggered());
+ assertEquals(50, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetRunning() {
+ AddressableLEDSim sim = AddressableLEDSim.createForIndex(0);
+ BooleanCallback callback = new BooleanCallback();
+ try (CallbackStore cb = sim.registerRunningCallback(callback, false);
+ AddressableLED led = new AddressableLED(0)) {
+ assertFalse(sim.getRunning());
+
+ led.start();
+ assertTrue(sim.getRunning());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+
+ callback.reset();
+ led.stop();
+ assertFalse(sim.getRunning());
+ assertTrue(callback.wasTriggered());
+ assertFalse(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetData() {
+ AddressableLEDSim sim = new AddressableLEDSim();
+ BufferCallback callback = new BufferCallback();
+
+ try (AddressableLED led = new AddressableLED(0);
+ CallbackStore cb = sim.registerDataCallback(callback); ) {
+ assertFalse(sim.getRunning());
+
+ assertEquals(1, sim.getLength()); // Defaults to 1 led
+
+ AddressableLEDBuffer ledData = new AddressableLEDBuffer(3);
+ led.setLength(ledData.getLength());
+
+ ledData.setRGB(0, 255, 0, 0);
+ ledData.setRGB(1, 0, 255, 0);
+ ledData.setRGB(2, 0, 0, 255);
+ led.setData(ledData);
+
+ byte[] data = sim.getData();
+ System.out.println(Arrays.toString(data));
+ assertEquals(12, data.length);
+
+ assertEquals((byte) 0, data[0]);
+ assertEquals((byte) 0, data[1]);
+ assertEquals((byte) 255, data[2]);
+ assertEquals((byte) 0, data[3]);
+
+ assertEquals((byte) 0, data[4]);
+ assertEquals((byte) 255, data[5]);
+ assertEquals((byte) 0, data[6]);
+ assertEquals((byte) 0, data[7]);
+
+ assertEquals((byte) 255, data[8]);
+ assertEquals((byte) 0, data[9]);
+ assertEquals((byte) 0, data[10]);
+ assertEquals((byte) 0, data[11]);
+
+ assertTrue(callback.wasTriggered());
+ data = callback.getSetValue();
+
+ assertEquals((byte) 0, data[0]);
+ assertEquals((byte) 0, data[1]);
+ assertEquals((byte) 255, data[2]);
+ assertEquals((byte) 0, data[3]);
+
+ assertEquals((byte) 0, data[4]);
+ assertEquals((byte) 255, data[5]);
+ assertEquals((byte) 0, data[6]);
+ assertEquals((byte) 0, data[7]);
+
+ assertEquals((byte) 255, data[8]);
+ assertEquals((byte) 0, data[9]);
+ assertEquals((byte) 0, data[10]);
+ assertEquals((byte) 0, data[11]);
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogEncoderSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogEncoderSimTest.java
index 677c5eb..5a04441 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogEncoderSimTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogEncoderSimTest.java
@@ -1,29 +1,27 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.wpilibj.AnalogEncoder;
import edu.wpi.first.wpilibj.AnalogInput;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
public class AnalogEncoderSimTest {
@Test
public void testBasic() {
- var analogInput = new AnalogInput(0);
- var analogEncoder = new AnalogEncoder(analogInput);
- var encoderSim = new AnalogEncoderSim(analogEncoder);
+ try (var analogInput = new AnalogInput(0);
+ var analogEncoder = new AnalogEncoder(analogInput)) {
+ var encoderSim = new AnalogEncoderSim(analogEncoder);
- encoderSim.setPosition(Rotation2d.fromDegrees(180));
- assertEquals(analogEncoder.get(), 0.5, 1E-8);
- assertEquals(encoderSim.getTurns(), 0.5, 1E-8);
- assertEquals(encoderSim.getPosition().getRadians(), Math.PI, 1E-8);
+ encoderSim.setPosition(Rotation2d.fromDegrees(180));
+ assertEquals(analogEncoder.get(), 0.5, 1E-8);
+ assertEquals(encoderSim.getTurns(), 0.5, 1E-8);
+ assertEquals(encoderSim.getPosition().getRadians(), Math.PI, 1E-8);
+ }
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogGyroSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogGyroSimTest.java
new file mode 100644
index 0000000..5ce5093
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogGyroSimTest.java
@@ -0,0 +1,97 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.hal.HAL;
+import edu.wpi.first.wpilibj.AnalogGyro;
+import edu.wpi.first.wpilibj.AnalogInput;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import org.junit.jupiter.api.Test;
+
+class AnalogGyroSimTest {
+ @Test
+ void testInitialization() {
+ HAL.initialize(500, 0);
+ AnalogGyroSim sim = new AnalogGyroSim(0);
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback initializedCallback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerInitializedCallback(initializedCallback, false);
+ AnalogInput ai = new AnalogInput(0);
+ AnalogGyro gyro = new AnalogGyro(ai)) {
+ assertTrue(sim.getInitialized());
+ assertTrue(initializedCallback.wasTriggered());
+ assertTrue(initializedCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetAngle() {
+ HAL.initialize(500, 0);
+
+ AnalogGyroSim sim = new AnalogGyroSim(0);
+ DoubleCallback callback = new DoubleCallback();
+
+ try (AnalogInput ai = new AnalogInput(0);
+ AnalogGyro gyro = new AnalogGyro(ai);
+ CallbackStore cb = sim.registerAngleCallback(callback, false)) {
+ assertEquals(0, gyro.getAngle());
+
+ final double TEST_ANGLE = 35.04;
+ sim.setAngle(TEST_ANGLE);
+ assertEquals(TEST_ANGLE, sim.getAngle());
+ assertEquals(TEST_ANGLE, gyro.getAngle());
+ assertEquals(-TEST_ANGLE, gyro.getRotation2d().getDegrees());
+ assertTrue(callback.wasTriggered());
+ assertEquals(TEST_ANGLE, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetRate() {
+ HAL.initialize(500, 0);
+
+ AnalogGyroSim sim = new AnalogGyroSim(0);
+ DoubleCallback callback = new DoubleCallback();
+
+ try (AnalogInput ai = new AnalogInput(0);
+ AnalogGyro gyro = new AnalogGyro(ai);
+ CallbackStore cb = sim.registerRateCallback(callback, false)) {
+ assertEquals(0, gyro.getRate());
+
+ final double TEST_RATE = -19.1;
+ sim.setRate(TEST_RATE);
+ assertEquals(TEST_RATE, sim.getRate());
+ assertEquals(TEST_RATE, gyro.getRate());
+
+ assertTrue(callback.wasTriggered());
+ assertEquals(TEST_RATE, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testReset() {
+ HAL.initialize(500, 0);
+
+ try (AnalogInput ai = new AnalogInput(0);
+ AnalogGyro gyro = new AnalogGyro(ai)) {
+ AnalogGyroSim sim = new AnalogGyroSim(gyro);
+ sim.setAngle(12.34);
+ sim.setRate(43.21);
+
+ sim.resetData();
+ assertEquals(0, sim.getAngle());
+ assertEquals(0, sim.getRate());
+ assertEquals(0, gyro.getAngle());
+ assertEquals(0, gyro.getRate());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogInputSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogInputSimTest.java
index a707725..ada4ebf 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogInputSimTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogInputSimTest.java
@@ -1,42 +1,86 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.hal.util.AllocationException;
+import edu.wpi.first.wpilibj.AnalogInput;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
import org.junit.jupiter.api.Test;
-import edu.wpi.first.wpilibj.AnalogInput;
-import edu.wpi.first.hal.HAL;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
class AnalogInputSimTest {
- static class DoubleStore {
- public boolean m_wasTriggered;
- public boolean m_wasCorrectType;
- public double m_setValue0;
+ @Test
+ void setInitializeTest() {
+ HAL.initialize(500, 0);
+
+ AnalogInputSim sim = new AnalogInputSim(5);
+ BooleanCallback callback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerInitializedCallback(callback, false);
+ AnalogInput input = new AnalogInput(5)) {
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
}
@Test
- void setCallbackTest() {
+ void testSetVoltage() {
HAL.initialize(500, 0);
- try (AnalogInput input = new AnalogInput(5)) {
- AnalogInputSim inputSim = new AnalogInputSim(input);
+ AnalogInputSim sim = new AnalogInputSim(5);
+ DoubleCallback callback = new DoubleCallback();
+
+ try (CallbackStore cb = sim.registerVoltageCallback(callback, false);
+ AnalogInput input = new AnalogInput(5)) {
+ // Bootstrap the voltage to be non-zero
+ sim.setVoltage(1.0);
for (double i = 0; i < 5.0; i += 0.1) {
- inputSim.setVoltage(0);
+ callback.reset();
+ sim.setVoltage(0);
assertEquals(input.getVoltage(), 0, 0.001);
- inputSim.setVoltage(i);
-
+ callback.reset();
+ sim.setVoltage(i);
assertEquals(input.getVoltage(), i, 0.001);
}
}
}
+
+ @Test
+ void testSetOverSampleBits() {
+ HAL.initialize(500, 0);
+ try (AnalogInput input = new AnalogInput(5)) {
+ input.setOversampleBits(3504);
+ assertEquals(3504, input.getOversampleBits());
+ }
+ }
+
+ @Test
+ void tesInitAccumulator() {
+ HAL.initialize(500, 0);
+ try (AnalogInput input = new AnalogInput(0)) {
+ // First initialization works fine
+ assertDoesNotThrow(input::initAccumulator);
+
+ input.resetAccumulator();
+ }
+ }
+
+ @Test
+ void tesInitAccumulatorOnInvalidPort() {
+ HAL.initialize(500, 0);
+ try (AnalogInput input = new AnalogInput(5)) {
+ assertThrows(AllocationException.class, input::initAccumulator);
+ }
+ }
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogOutputSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogOutputSimTest.java
index fe1bba8..85a7494 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogOutputSimTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogOutputSimTest.java
@@ -1,31 +1,32 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import edu.wpi.first.wpilibj.AnalogOutput;
-import edu.wpi.first.hal.HAL;
-
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.hal.HAL;
+import edu.wpi.first.wpilibj.AnalogOutput;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
import org.junit.jupiter.api.Test;
class AnalogOutputSimTest {
- static class DoubleStore {
- public boolean m_wasTriggered;
- public boolean m_wasCorrectType;
- public double m_setValue = -1;
+ @Test
+ void testInitialization() {
+ HAL.initialize(500, 0);
- public void reset() {
- m_wasCorrectType = false;
- m_wasTriggered = false;
- m_setValue = -1;
+ AnalogOutputSim outputSim = new AnalogOutputSim(0);
+ assertFalse(outputSim.getInitialized());
+
+ BooleanCallback callback = new BooleanCallback();
+
+ try (CallbackStore cb = outputSim.registerInitializedCallback(callback, false);
+ AnalogOutput output = new AnalogOutput(0)) {
+ assertTrue(outputSim.getInitialized());
}
}
@@ -33,37 +34,51 @@
void setCallbackTest() {
HAL.initialize(500, 0);
-
try (AnalogOutput output = new AnalogOutput(0)) {
output.setVoltage(0.5);
AnalogOutputSim outputSim = new AnalogOutputSim(output);
- DoubleStore store = new DoubleStore();
+ DoubleCallback voltageCallback = new DoubleCallback();
- try (CallbackStore cb = outputSim.registerVoltageCallback((name, value) -> {
- store.m_wasTriggered = true;
- store.m_wasCorrectType = true;
- store.m_setValue = value.getDouble();
- }, false)) {
- assertFalse(store.m_wasTriggered);
+ try (CallbackStore cb = outputSim.registerVoltageCallback(voltageCallback, false)) {
+ assertFalse(voltageCallback.wasTriggered());
for (double i = 0.1; i < 5.0; i += 0.1) {
- store.reset();
+ voltageCallback.reset();
output.setVoltage(0);
- assertTrue(store.m_wasTriggered);
- assertEquals(store.m_setValue, 0, 0.001);
+ assertEquals(0, output.getVoltage());
+ assertEquals(0, outputSim.getVoltage());
+ assertTrue(voltageCallback.wasTriggered());
+ assertEquals(voltageCallback.getSetValue(), 0, 0.001);
- store.reset();
+ voltageCallback.reset();
output.setVoltage(i);
- assertTrue(store.m_wasTriggered);
- assertEquals(store.m_setValue, i, 0.001);
+ assertEquals(i, output.getVoltage());
+ assertEquals(i, outputSim.getVoltage());
+ assertTrue(voltageCallback.wasTriggered());
+ assertEquals(voltageCallback.getSetValue(), i, 0.001);
}
}
}
}
+
+ @Test
+ void testReset() {
+ HAL.initialize(500, 0);
+
+ AnalogOutputSim outputSim = new AnalogOutputSim(0);
+
+ try (AnalogOutput output = new AnalogOutput(0)) {
+ output.setVoltage(1.2);
+
+ outputSim.resetData();
+ assertEquals(0, output.getVoltage());
+ assertEquals(0, outputSim.getVoltage());
+ }
+ }
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogTriggerSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogTriggerSimTest.java
new file mode 100644
index 0000000..1142914
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/AnalogTriggerSimTest.java
@@ -0,0 +1,59 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.hal.HAL;
+import edu.wpi.first.wpilibj.AnalogTrigger;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import org.junit.jupiter.api.Test;
+
+class AnalogTriggerSimTest {
+ @Test
+ void testInitialization() {
+ HAL.initialize(500, 0);
+
+ AnalogTriggerSim sim = AnalogTriggerSim.createForIndex(0);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback callback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerInitializedCallback(callback, false);
+ AnalogTrigger trigger = new AnalogTrigger(0)) {
+ assertTrue(sim.getInitialized());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void triggerLowerBoundTest() {
+ HAL.initialize(500, 0);
+
+ try (AnalogTrigger trigger = new AnalogTrigger(0)) {
+ AnalogTriggerSim sim = new AnalogTriggerSim(trigger);
+ DoubleCallback lowerCallback = new DoubleCallback();
+ DoubleCallback upperCallback = new DoubleCallback();
+ try (CallbackStore lowerCb = sim.registerTriggerLowerBoundCallback(lowerCallback, false);
+ CallbackStore upperCb = sim.registerTriggerUpperBoundCallback(upperCallback, false)) {
+ trigger.setLimitsVoltage(0.299, 1.91);
+
+ assertEquals(0.299, sim.getTriggerLowerBound());
+ assertEquals(1.91, sim.getTriggerUpperBound());
+
+ assertTrue(lowerCallback.wasTriggered());
+ assertEquals(0.299, lowerCallback.getSetValue());
+
+ assertTrue(upperCallback.wasTriggered());
+ assertEquals(1.91, upperCallback.getSetValue());
+ }
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/CTREPCMSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/CTREPCMSimTest.java
new file mode 100644
index 0000000..29cac3a
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/CTREPCMSimTest.java
@@ -0,0 +1,168 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.DoubleSolenoid;
+import edu.wpi.first.wpilibj.PneumaticsControlModule;
+import edu.wpi.first.wpilibj.PneumaticsModuleType;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import org.junit.jupiter.api.Test;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+class CTREPCMSimTest {
+ @Test
+ void testInitialization() {
+ HAL.initialize(500, 0);
+
+ CTREPCMSim sim = new CTREPCMSim(0);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback callback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerInitializedCallback(callback, false);
+ PneumaticsControlModule pcm = new PneumaticsControlModule(0)) {
+ assertTrue(sim.getInitialized());
+ }
+ assertFalse(sim.getInitialized());
+ }
+
+ @Test
+ void solenoidOutputTest() {
+ HAL.initialize(500, 0);
+
+ try (PneumaticsControlModule pcm = new PneumaticsControlModule(0);
+ DoubleSolenoid doubleSolenoid = new DoubleSolenoid(0, PneumaticsModuleType.CTREPCM, 3, 4)) {
+ CTREPCMSim sim = new CTREPCMSim(0);
+ sim.resetData();
+
+ BooleanCallback callback3 = new BooleanCallback();
+ BooleanCallback callback4 = new BooleanCallback();
+
+ try (CallbackStore cb3 = sim.registerSolenoidOutputCallback(3, callback3, false);
+ CallbackStore cb4 = sim.registerSolenoidOutputCallback(4, callback4, false)) {
+ // Reverse
+ callback3.reset();
+ callback4.reset();
+ doubleSolenoid.set(DoubleSolenoid.Value.kReverse);
+ assertFalse(callback3.wasTriggered());
+ assertNull(callback3.getSetValue());
+ assertTrue(callback4.wasTriggered());
+ assertTrue(callback4.getSetValue());
+ assertFalse(sim.getSolenoidOutput(3));
+ assertTrue(sim.getSolenoidOutput(4));
+ assertEquals(0x10, pcm.getSolenoids());
+
+ // Forward
+ callback3.reset();
+ callback4.reset();
+ doubleSolenoid.set(DoubleSolenoid.Value.kForward);
+ assertTrue(callback3.wasTriggered());
+ assertTrue(callback3.getSetValue());
+ assertTrue(callback4.wasTriggered());
+ assertFalse(callback4.getSetValue());
+ assertTrue(sim.getSolenoidOutput(3));
+ assertFalse(sim.getSolenoidOutput(4));
+ assertEquals(0x8, pcm.getSolenoids());
+
+ // Off
+ callback3.reset();
+ callback4.reset();
+ doubleSolenoid.set(DoubleSolenoid.Value.kOff);
+ assertTrue(callback3.wasTriggered());
+ assertFalse(callback3.getSetValue());
+ assertFalse(callback4.wasTriggered());
+ assertNull(callback4.getSetValue());
+ assertFalse(sim.getSolenoidOutput(3));
+ assertFalse(sim.getSolenoidOutput(4));
+ assertEquals(0x0, pcm.getSolenoids());
+ }
+ }
+ }
+
+ @Test
+ void setCompressorOnTest() {
+ HAL.initialize(500, 0);
+
+ CTREPCMSim sim = new CTREPCMSim(0);
+ BooleanCallback callback = new BooleanCallback();
+
+ try (PneumaticsControlModule pcm = new PneumaticsControlModule(0);
+ CallbackStore cb = sim.registerCompressorOnCallback(callback, false)) {
+ assertFalse(pcm.getCompressor());
+ assertFalse(sim.getCompressorOn());
+ sim.setCompressorOn(true);
+ assertTrue(pcm.getCompressor());
+ assertTrue(sim.getCompressorOn());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void setClosedLoopEnabled() {
+ HAL.initialize(500, 0);
+
+ CTREPCMSim sim = new CTREPCMSim(0);
+ BooleanCallback callback = new BooleanCallback();
+
+ try (PneumaticsControlModule pcm = new PneumaticsControlModule(0);
+ CallbackStore cb = sim.registerClosedLoopEnabledCallback(callback, false)) {
+ pcm.setClosedLoopControl(false);
+ assertFalse(pcm.getClosedLoopControl());
+
+ pcm.setClosedLoopControl(true);
+ assertTrue(sim.getClosedLoopEnabled());
+ assertTrue(pcm.getClosedLoopControl());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void setPressureSwitchEnabledTest() {
+ HAL.initialize(500, 0);
+
+ CTREPCMSim sim = new CTREPCMSim(0);
+ BooleanCallback callback = new BooleanCallback();
+
+ try (PneumaticsControlModule pcm = new PneumaticsControlModule(0);
+ CallbackStore cb = sim.registerPressureSwitchCallback(callback, false)) {
+ assertFalse(pcm.getPressureSwitch());
+
+ sim.setPressureSwitch(true);
+ assertTrue(sim.getPressureSwitch());
+ assertTrue(pcm.getPressureSwitch());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void setCompressorCurrentTest() {
+ HAL.initialize(500, 0);
+
+ CTREPCMSim sim = new CTREPCMSim(0);
+ DoubleCallback callback = new DoubleCallback();
+
+ try (PneumaticsControlModule pcm = new PneumaticsControlModule(0);
+ CallbackStore cb = sim.registerCompressorCurrentCallback(callback, false)) {
+ assertFalse(pcm.getPressureSwitch());
+
+ sim.setCompressorCurrent(35.04);
+ assertEquals(35.04, sim.getCompressorCurrent());
+ assertEquals(35.04, pcm.getCompressorCurrent());
+ assertTrue(callback.wasTriggered());
+ assertEquals(35.04, callback.getSetValue());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DIOSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DIOSimTest.java
new file mode 100644
index 0000000..1c742fe
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DIOSimTest.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.wpilibj.simulation;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.DigitalInput;
+import edu.wpi.first.wpilibj.DigitalOutput;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import org.junit.jupiter.api.Test;
+
+class DIOSimTest {
+ @Test
+ void testInitialization() {
+ DIOSim sim = new DIOSim(2);
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback initializedCallback = new BooleanCallback();
+ BooleanCallback isInputCallback = new BooleanCallback();
+
+ try (CallbackStore initializeCb = sim.registerInitializedCallback(initializedCallback, false);
+ CallbackStore inputCb = sim.registerIsInputCallback(isInputCallback, false);
+ DigitalOutput output = new DigitalOutput(2)) {
+ assertTrue(sim.getInitialized());
+ assertTrue(initializedCallback.wasTriggered());
+ assertTrue(initializedCallback.getSetValue());
+
+ assertFalse(sim.getIsInput());
+ assertTrue(isInputCallback.wasTriggered());
+ assertFalse(isInputCallback.getSetValue());
+
+ initializedCallback.reset();
+ sim.setInitialized(false);
+ assertTrue(initializedCallback.wasTriggered());
+ assertFalse(initializedCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testInput() {
+ HAL.initialize(500, 0);
+
+ try (DigitalInput input = new DigitalInput(0)) {
+ DIOSim sim = new DIOSim(input);
+ assertTrue(sim.getIsInput());
+
+ BooleanCallback valueCallback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerValueCallback(valueCallback, false)) {
+ assertTrue(input.get());
+ assertTrue(sim.getValue());
+
+ assertFalse(valueCallback.wasTriggered());
+ sim.setValue(false);
+ assertTrue(valueCallback.wasTriggered());
+ assertFalse(valueCallback.getSetValue());
+ }
+ }
+ }
+
+ @Test
+ void testOutput() {
+ HAL.initialize(500, 0);
+ try (DigitalOutput output = new DigitalOutput(0)) {
+ DIOSim sim = new DIOSim(output);
+ assertFalse(sim.getIsInput());
+
+ BooleanCallback valueCallback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerValueCallback(valueCallback, false)) {
+ assertFalse(output.get());
+ assertFalse(sim.getValue());
+
+ assertFalse(valueCallback.wasTriggered());
+ output.set(true);
+ assertTrue(valueCallback.wasTriggered());
+ assertTrue(valueCallback.getSetValue());
+ }
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DifferentialDrivetrainSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DifferentialDrivetrainSimTest.java
index 4a0eab3..62fdcc9 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DifferentialDrivetrainSimTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DifferentialDrivetrainSimTest.java
@@ -1,53 +1,50 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import edu.wpi.first.wpilibj.controller.LinearPlantInversionFeedforward;
-import edu.wpi.first.wpilibj.controller.RamseteController;
-import edu.wpi.first.wpilibj.geometry.Pose2d;
-import edu.wpi.first.wpilibj.geometry.Rotation2d;
-import edu.wpi.first.wpilibj.kinematics.DifferentialDriveKinematics;
-import edu.wpi.first.wpilibj.system.RungeKutta;
-import edu.wpi.first.wpilibj.system.plant.DCMotor;
-import edu.wpi.first.wpilibj.system.plant.LinearSystemId;
-import edu.wpi.first.wpilibj.trajectory.TrajectoryConfig;
-import edu.wpi.first.wpilibj.trajectory.TrajectoryGenerator;
-import edu.wpi.first.wpilibj.trajectory.constraint.DifferentialDriveKinematicsConstraint;
-import edu.wpi.first.wpilibj.util.Units;
-import edu.wpi.first.wpiutil.math.Matrix;
-import edu.wpi.first.wpiutil.math.Nat;
-import edu.wpi.first.wpiutil.math.VecBuilder;
-import edu.wpi.first.wpiutil.math.Vector;
-import edu.wpi.first.wpiutil.math.numbers.N1;
-import edu.wpi.first.wpiutil.math.numbers.N7;
-
-import org.junit.jupiter.api.Test;
-
-import java.util.List;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import edu.wpi.first.math.Matrix;
+import edu.wpi.first.math.Nat;
+import edu.wpi.first.math.VecBuilder;
+import edu.wpi.first.math.Vector;
+import edu.wpi.first.math.controller.LinearPlantInversionFeedforward;
+import edu.wpi.first.math.controller.RamseteController;
+import edu.wpi.first.math.geometry.Pose2d;
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.math.kinematics.DifferentialDriveKinematics;
+import edu.wpi.first.math.numbers.N1;
+import edu.wpi.first.math.numbers.N7;
+import edu.wpi.first.math.system.NumericalIntegration;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.math.system.plant.LinearSystemId;
+import edu.wpi.first.math.trajectory.TrajectoryConfig;
+import edu.wpi.first.math.trajectory.TrajectoryGenerator;
+import edu.wpi.first.math.trajectory.constraint.DifferentialDriveKinematicsConstraint;
+import edu.wpi.first.math.util.Units;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
class DifferentialDrivetrainSimTest {
@Test
public void testConvergence() {
var motor = DCMotor.getNEO(2);
- var plant = LinearSystemId.createDrivetrainVelocitySystem(
- motor,
- 50,
- Units.inchesToMeters(2),
- Units.inchesToMeters(12),
- 0.5,
- 1.0);
+ var plant =
+ LinearSystemId.createDrivetrainVelocitySystem(
+ motor, 50, Units.inchesToMeters(2), Units.inchesToMeters(12), 0.5, 1.0);
var kinematics = new DifferentialDriveKinematics(Units.inchesToMeters(24));
- var sim = new DifferentialDrivetrainSim(plant,
- motor, 1, kinematics.trackWidthMeters, Units.inchesToMeters(2));
+ var sim =
+ new DifferentialDrivetrainSim(
+ plant,
+ motor,
+ 1,
+ kinematics.trackWidthMeters,
+ Units.inchesToMeters(2),
+ VecBuilder.fill(0, 0, 0.0001, 0.1, 0.1, 0.005, 0.005));
var feedforward = new LinearPlantInversionFeedforward<>(plant, 0.020);
var ramsete = new RamseteController();
@@ -56,12 +53,13 @@
// ground truth
Matrix<N7, N1> groundTruthX = new Vector<>(Nat.N7());
- var traj = TrajectoryGenerator.generateTrajectory(
- new Pose2d(),
- List.of(),
- new Pose2d(2, 2, new Rotation2d()),
- new TrajectoryConfig(1, 1)
- .addConstraint(new DifferentialDriveKinematicsConstraint(kinematics, 1)));
+ var traj =
+ TrajectoryGenerator.generateTrajectory(
+ new Pose2d(),
+ List.of(),
+ new Pose2d(2, 2, new Rotation2d()),
+ new TrajectoryConfig(1, 1)
+ .addConstraint(new DifferentialDriveKinematicsConstraint(kinematics, 1)));
for (double t = 0; t < traj.getTotalTimeSeconds(); t += 0.020) {
var state = traj.sample(0.020);
@@ -69,37 +67,44 @@
var wheelSpeeds = kinematics.toWheelSpeeds(ramseteOut);
- var voltages = feedforward.calculate(
- VecBuilder.fill(wheelSpeeds.leftMetersPerSecond, wheelSpeeds.rightMetersPerSecond));
+ var voltages =
+ feedforward.calculate(
+ VecBuilder.fill(wheelSpeeds.leftMetersPerSecond, wheelSpeeds.rightMetersPerSecond));
// Sim periodic code
sim.setInputs(voltages.get(0, 0), voltages.get(1, 0));
sim.update(0.020);
// Update our ground truth
- groundTruthX = RungeKutta.rungeKutta(sim::getDynamics, groundTruthX, voltages, 0.020);
+ groundTruthX = NumericalIntegration.rk4(sim::getDynamics, groundTruthX, voltages, 0.020);
}
- assertEquals(groundTruthX.get(DifferentialDrivetrainSim.State.kX.value, 0),
- sim.getState(DifferentialDrivetrainSim.State.kX));
- assertEquals(groundTruthX.get(DifferentialDrivetrainSim.State.kY.value, 0),
- sim.getState(DifferentialDrivetrainSim.State.kY));
- assertEquals(groundTruthX.get(DifferentialDrivetrainSim.State.kHeading.value, 0),
- sim.getState(DifferentialDrivetrainSim.State.kHeading));
+ // 2 inch tolerance is OK since our ground truth is an approximation of the
+ // ODE solution using RK4 anyway
+ assertEquals(
+ groundTruthX.get(DifferentialDrivetrainSim.State.kX.value, 0),
+ sim.getState(DifferentialDrivetrainSim.State.kX),
+ 0.05);
+ assertEquals(
+ groundTruthX.get(DifferentialDrivetrainSim.State.kY.value, 0),
+ sim.getState(DifferentialDrivetrainSim.State.kY),
+ 0.05);
+ assertEquals(
+ groundTruthX.get(DifferentialDrivetrainSim.State.kHeading.value, 0),
+ sim.getState(DifferentialDrivetrainSim.State.kHeading),
+ 0.01);
}
@Test
public void testCurrent() {
var motor = DCMotor.getNEO(2);
- var plant = LinearSystemId.createDrivetrainVelocitySystem(
- motor,
- 50,
- Units.inchesToMeters(2),
- Units.inchesToMeters(12),
- 0.5,
- 1.0);
+ var plant =
+ LinearSystemId.createDrivetrainVelocitySystem(
+ motor, 50, Units.inchesToMeters(2), Units.inchesToMeters(12), 0.5, 1.0);
var kinematics = new DifferentialDriveKinematics(Units.inchesToMeters(24));
- var sim = new DifferentialDrivetrainSim(plant, motor, 1, kinematics.trackWidthMeters, Units.inchesToMeters(2));
+ var sim =
+ new DifferentialDrivetrainSim(
+ plant, motor, 1, kinematics.trackWidthMeters, Units.inchesToMeters(2), null);
sim.setInputs(-12, -12);
for (int i = 0; i < 10; i++) {
@@ -123,16 +128,19 @@
@Test
public void testModelStability() {
var motor = DCMotor.getNEO(2);
- var plant = LinearSystemId.createDrivetrainVelocitySystem(
- motor,
- 50,
- Units.inchesToMeters(2),
- Units.inchesToMeters(12),
- 2.0,
- 5.0);
+ var plant =
+ LinearSystemId.createDrivetrainVelocitySystem(
+ motor, 50, Units.inchesToMeters(2), Units.inchesToMeters(12), 2.0, 5.0);
var kinematics = new DifferentialDriveKinematics(Units.inchesToMeters(24));
- var sim = new DifferentialDrivetrainSim(plant, motor, 5, kinematics.trackWidthMeters, Units.inchesToMeters(2));
+ var sim =
+ new DifferentialDrivetrainSim(
+ plant,
+ motor,
+ 5,
+ kinematics.trackWidthMeters,
+ Units.inchesToMeters(2),
+ VecBuilder.fill(0, 0, 0.0001, 0.1, 0.1, 0.005, 0.005));
sim.setInputs(2, 4);
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DigitalPWMSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DigitalPWMSimTest.java
new file mode 100644
index 0000000..9f29aac
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DigitalPWMSimTest.java
@@ -0,0 +1,58 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.hal.HAL;
+import edu.wpi.first.wpilibj.DigitalOutput;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.IntCallback;
+import org.junit.jupiter.api.Test;
+
+class DigitalPWMSimTest {
+ @Test
+ void testInitialization() {
+ try (DigitalOutput output = new DigitalOutput(0)) {
+ DigitalPWMSim sim = new DigitalPWMSim(output);
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback initializeCallback = new BooleanCallback();
+ DoubleCallback dutyCycleCallback = new DoubleCallback();
+ try (CallbackStore initCb = sim.registerInitializedCallback(initializeCallback, false);
+ CallbackStore dutyCycleCb = sim.registerDutyCycleCallback(dutyCycleCallback, false); ) {
+ final double kTestDutyCycle = 0.191;
+ output.enablePWM(kTestDutyCycle);
+
+ assertTrue(sim.getInitialized());
+ assertTrue(initializeCallback.wasTriggered());
+ assertTrue(initializeCallback.getSetValue());
+
+ assertEquals(kTestDutyCycle, sim.getDutyCycle());
+ assertTrue(dutyCycleCallback.wasTriggered());
+ assertEquals(kTestDutyCycle, dutyCycleCallback.getSetValue());
+ }
+ }
+ }
+
+ @Test
+ void setPinTest() {
+ HAL.initialize(500, 0);
+
+ try (DigitalOutput output = new DigitalOutput(0)) {
+ DigitalPWMSim sim = new DigitalPWMSim(output);
+ IntCallback callback = new IntCallback();
+ try (CallbackStore cb = sim.registerPinCallback(callback, false)) {
+ sim.setPin(191);
+ assertEquals(191, sim.getPin());
+ assertTrue(callback.wasTriggered());
+ assertEquals(191, callback.getSetValue());
+ }
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DriverStationSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DriverStationSimTest.java
new file mode 100644
index 0000000..ce50afc
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DriverStationSimTest.java
@@ -0,0 +1,261 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.hal.AllianceStationID;
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.EnumCallback;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+public class DriverStationSimTest {
+ @Test
+ void testEnabled() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ assertFalse(DriverStation.isEnabled());
+ BooleanCallback callback = new BooleanCallback();
+ try (CallbackStore cb = DriverStationSim.registerEnabledCallback(callback, false)) {
+ DriverStationSim.setEnabled(true);
+ DriverStationSim.notifyNewData();
+ assertTrue(DriverStationSim.getEnabled());
+ assertTrue(DriverStation.isEnabled());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testAutonomus() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ assertFalse(DriverStation.isAutonomous());
+ BooleanCallback callback = new BooleanCallback();
+ try (CallbackStore cb = DriverStationSim.registerAutonomousCallback(callback, false)) {
+ DriverStationSim.setAutonomous(true);
+ DriverStationSim.notifyNewData();
+ assertTrue(DriverStationSim.getAutonomous());
+ assertTrue(DriverStation.isAutonomous());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testTest() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ assertFalse(DriverStation.isTest());
+ BooleanCallback callback = new BooleanCallback();
+ try (CallbackStore cb = DriverStationSim.registerTestCallback(callback, false)) {
+ DriverStationSim.setTest(true);
+ DriverStationSim.notifyNewData();
+ assertTrue(DriverStationSim.getTest());
+ assertTrue(DriverStation.isTest());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testEstop() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ assertFalse(DriverStation.isEStopped());
+ BooleanCallback callback = new BooleanCallback();
+ try (CallbackStore cb = DriverStationSim.registerEStopCallback(callback, false)) {
+ DriverStationSim.setEStop(true);
+ DriverStationSim.notifyNewData();
+ assertTrue(DriverStationSim.getEStop());
+ assertTrue(DriverStation.isEStopped());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testFmsAttached() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ assertFalse(DriverStation.isFMSAttached());
+ BooleanCallback callback = new BooleanCallback();
+ try (CallbackStore cb = DriverStationSim.registerFmsAttachedCallback(callback, false)) {
+ DriverStationSim.setFmsAttached(true);
+ DriverStationSim.notifyNewData();
+ assertTrue(DriverStationSim.getFmsAttached());
+ assertTrue(DriverStation.isFMSAttached());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testDsAttached() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ DriverStationSim.notifyNewData();
+ assertTrue(DriverStation.isDSAttached());
+
+ BooleanCallback callback = new BooleanCallback();
+ try (CallbackStore cb = DriverStationSim.registerDsAttachedCallback(callback, false)) {
+ DriverStationSim.setDsAttached(false);
+ DriverStationSim.notifyNewData();
+ assertFalse(DriverStationSim.getDsAttached());
+ assertFalse(DriverStation.isDSAttached());
+ assertTrue(callback.wasTriggered());
+ assertFalse(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testAllianceStationId() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ EnumCallback callback = new EnumCallback();
+
+ AllianceStationID allianceStation = AllianceStationID.Blue2;
+ DriverStationSim.setAllianceStationId(allianceStation);
+
+ try (CallbackStore cb = DriverStationSim.registerAllianceStationIdCallback(callback, false)) {
+ // B1
+ allianceStation = AllianceStationID.Blue1;
+ DriverStationSim.setAllianceStationId(allianceStation);
+ assertEquals(allianceStation, DriverStationSim.getAllianceStationId());
+ assertEquals(DriverStation.Alliance.Blue, DriverStation.getAlliance());
+ assertEquals(1, DriverStation.getLocation());
+ assertTrue(callback.wasTriggered());
+ assertEquals(allianceStation.ordinal(), callback.getSetValue());
+
+ // B2
+ allianceStation = AllianceStationID.Blue2;
+ DriverStationSim.setAllianceStationId(allianceStation);
+ assertEquals(allianceStation, DriverStationSim.getAllianceStationId());
+ assertEquals(DriverStation.Alliance.Blue, DriverStation.getAlliance());
+ assertEquals(2, DriverStation.getLocation());
+ assertTrue(callback.wasTriggered());
+ assertEquals(allianceStation.ordinal(), callback.getSetValue());
+
+ // B3
+ allianceStation = AllianceStationID.Blue3;
+ DriverStationSim.setAllianceStationId(allianceStation);
+ assertEquals(allianceStation, DriverStationSim.getAllianceStationId());
+ assertEquals(DriverStation.Alliance.Blue, DriverStation.getAlliance());
+ assertEquals(3, DriverStation.getLocation());
+ assertTrue(callback.wasTriggered());
+ assertEquals(allianceStation.ordinal(), callback.getSetValue());
+
+ // R1
+ allianceStation = AllianceStationID.Red1;
+ DriverStationSim.setAllianceStationId(allianceStation);
+ assertEquals(allianceStation, DriverStationSim.getAllianceStationId());
+ assertEquals(DriverStation.Alliance.Red, DriverStation.getAlliance());
+ assertEquals(1, DriverStation.getLocation());
+ assertTrue(callback.wasTriggered());
+ assertEquals(allianceStation.ordinal(), callback.getSetValue());
+
+ // R2
+ allianceStation = AllianceStationID.Red2;
+ DriverStationSim.setAllianceStationId(allianceStation);
+ assertEquals(allianceStation, DriverStationSim.getAllianceStationId());
+ assertEquals(DriverStation.Alliance.Red, DriverStation.getAlliance());
+ assertEquals(2, DriverStation.getLocation());
+ assertTrue(callback.wasTriggered());
+ assertEquals(allianceStation.ordinal(), callback.getSetValue());
+
+ // R3
+ allianceStation = AllianceStationID.Red3;
+ DriverStationSim.setAllianceStationId(allianceStation);
+ assertEquals(allianceStation, DriverStationSim.getAllianceStationId());
+ assertEquals(DriverStation.Alliance.Red, DriverStation.getAlliance());
+ assertEquals(3, DriverStation.getLocation());
+ assertTrue(callback.wasTriggered());
+ assertEquals(allianceStation.ordinal(), callback.getSetValue());
+ }
+ }
+
+ @ParameterizedTest
+ @EnumSource(DriverStation.MatchType.class)
+ public void testMatchType(DriverStation.MatchType matchType) {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ DriverStationSim.setMatchType(matchType);
+ DriverStationSim.notifyNewData();
+ assertEquals(matchType, DriverStation.getMatchType());
+ }
+
+ @Test
+ public void testReplayNumber() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ DriverStationSim.setReplayNumber(4);
+ DriverStationSim.notifyNewData();
+ assertEquals(4, DriverStation.getReplayNumber());
+ }
+
+ @Test
+ public void testMatchNumber() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ DriverStationSim.setMatchNumber(3);
+ DriverStationSim.notifyNewData();
+ assertEquals(3, DriverStation.getMatchNumber());
+ }
+
+ @Test
+ public void testMatchTime() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ DoubleCallback callback = new DoubleCallback();
+ try (CallbackStore cb = DriverStationSim.registerMatchTimeCallback(callback, false)) {
+ final double testTime = 19.174;
+ DriverStationSim.setMatchTime(testTime);
+ assertEquals(testTime, DriverStationSim.getMatchTime());
+ assertEquals(testTime, DriverStation.getMatchTime());
+ assertTrue(callback.wasTriggered());
+ assertEquals(testTime, callback.getSetValue());
+ }
+ }
+
+ @Test
+ public void testSetGameSpecificMessage() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ final String message = "Hello World!";
+ DriverStationSim.setGameSpecificMessage(message);
+ DriverStationSim.notifyNewData();
+ assertEquals(message, DriverStation.getGameSpecificMessage());
+ }
+
+ @Test
+ public void testSetEventName() {
+ HAL.initialize(500, 0);
+ DriverStationSim.resetData();
+
+ final String message = "The Best Event";
+ DriverStationSim.setEventName(message);
+ DriverStationSim.notifyNewData();
+ assertEquals(message, DriverStation.getEventName());
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DutyCycleEncoderSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DutyCycleEncoderSimTest.java
new file mode 100644
index 0000000..49f8e77
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DutyCycleEncoderSimTest.java
@@ -0,0 +1,35 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.DutyCycleEncoder;
+import org.junit.jupiter.api.Test;
+
+class DutyCycleEncoderSimTest {
+ @Test
+ void setTest() {
+ try (DutyCycleEncoder encoder = new DutyCycleEncoder(0)) {
+ DutyCycleEncoderSim sim = new DutyCycleEncoderSim(encoder);
+
+ sim.set(5.67);
+ assertEquals(5.67, encoder.get());
+ }
+ }
+
+ @Test
+ void setDistanceTest() {
+ HAL.initialize(500, 0);
+
+ try (DutyCycleEncoder encoder = new DutyCycleEncoder(0)) {
+ DutyCycleEncoderSim sim = new DutyCycleEncoderSim(encoder);
+
+ sim.setDistance(19.1);
+ assertEquals(19.1, encoder.getDistance());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DutyCycleSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DutyCycleSimTest.java
new file mode 100644
index 0000000..3c2a7fe
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/DutyCycleSimTest.java
@@ -0,0 +1,71 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.hal.HAL;
+import edu.wpi.first.wpilibj.DigitalInput;
+import edu.wpi.first.wpilibj.DutyCycle;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.IntCallback;
+import org.junit.jupiter.api.Test;
+
+class DutyCycleSimTest {
+ @Test
+ void testInitialization() {
+ DutyCycleSim sim = DutyCycleSim.createForIndex(0);
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback callback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerInitializedCallback(callback, false);
+ DigitalInput di = new DigitalInput(2);
+ DutyCycle dc = new DutyCycle(di)) {
+ assertTrue(sim.getInitialized());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void setFrequencyTest() {
+ HAL.initialize(500, 0);
+
+ try (DigitalInput di = new DigitalInput(2);
+ DutyCycle dc = new DutyCycle(di)) {
+ IntCallback callback = new IntCallback();
+ DutyCycleSim sim = new DutyCycleSim(dc);
+ try (CallbackStore cb = sim.registerFrequencyCallback(callback, false)) {
+ sim.setFrequency(191);
+ assertEquals(191, sim.getFrequency());
+ assertEquals(191, dc.getFrequency());
+ assertTrue(callback.wasTriggered());
+ assertEquals(191, callback.getSetValue());
+ }
+ }
+ }
+
+ @Test
+ void setOutputTest() {
+ HAL.initialize(500, 0);
+
+ try (DigitalInput di = new DigitalInput(2);
+ DutyCycle dc = new DutyCycle(di)) {
+ DoubleCallback callback = new DoubleCallback();
+ DutyCycleSim sim = new DutyCycleSim(dc);
+ try (CallbackStore cb = sim.registerOutputCallback(callback, false)) {
+ sim.setOutput(229.174);
+ assertEquals(229.174, sim.getOutput());
+ assertEquals(229.174, dc.getOutput());
+ assertTrue(callback.wasTriggered());
+ assertEquals(229.174, callback.getSetValue());
+ }
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ElevatorSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ElevatorSimTest.java
index c4d78d0..d655a90 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ElevatorSimTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/ElevatorSimTest.java
@@ -1,70 +1,80 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.wpilibj.Encoder;
-import edu.wpi.first.wpilibj.PWMVictorSPX;
-import edu.wpi.first.wpilibj.RobotController;
-import edu.wpi.first.wpilibj.controller.PIDController;
-import edu.wpi.first.wpilibj.system.plant.DCMotor;
-import edu.wpi.first.wpilibj.system.plant.LinearSystemId;
-import edu.wpi.first.wpiutil.math.VecBuilder;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import edu.wpi.first.math.VecBuilder;
+import edu.wpi.first.math.controller.PIDController;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.math.system.plant.LinearSystemId;
+import edu.wpi.first.math.util.Units;
+import edu.wpi.first.wpilibj.Encoder;
+import edu.wpi.first.wpilibj.RobotController;
+import edu.wpi.first.wpilibj.motorcontrol.PWMVictorSPX;
+import org.junit.jupiter.api.Test;
+
public class ElevatorSimTest {
@Test
- @SuppressWarnings("LocalVariableName")
+ @SuppressWarnings({"LocalVariableName", "resource"})
public void testStateSpaceSimWithElevator() {
+ RoboRioSim.resetData();
var controller = new PIDController(10, 0, 0);
- var sim = new ElevatorSim(DCMotor.getVex775Pro(4), 14.67, 8, 0.75 * 25.4 / 1000.0,
- 0.0, 3.0, VecBuilder.fill(0.01));
+ var sim =
+ new ElevatorSim(
+ DCMotor.getVex775Pro(4),
+ 14.67,
+ 8,
+ 0.75 * 25.4 / 1000.0,
+ 0.0,
+ 3.0,
+ VecBuilder.fill(0.01));
- var motor = new PWMVictorSPX(0);
- var encoder = new Encoder(0, 1);
- var encoderSim = new EncoderSim(encoder);
+ try (var motor = new PWMVictorSPX(0);
+ var encoder = new Encoder(0, 1)) {
+ var encoderSim = new EncoderSim(encoder);
- for (int i = 0; i < 100; i++) {
- controller.setSetpoint(2.0);
+ for (int i = 0; i < 100; i++) {
+ controller.setSetpoint(2.0);
- double nextVoltage = controller.calculate(encoderSim.getDistance());
+ double nextVoltage = controller.calculate(encoderSim.getDistance());
- double currentBatteryVoltage = RobotController.getBatteryVoltage();
- motor.set(nextVoltage / currentBatteryVoltage);
+ double currentBatteryVoltage = RobotController.getBatteryVoltage();
+ motor.set(nextVoltage / currentBatteryVoltage);
- // ------ SimulationPeriodic() happens after user code -------
+ // ------ SimulationPeriodic() happens after user code -------
- var u = VecBuilder.fill(motor.get() * currentBatteryVoltage);
- sim.setInput(u);
- sim.update(0.020);
- var y = sim.getOutput();
- encoderSim.setDistance(y.get(0, 0));
+ var u = VecBuilder.fill(motor.get() * currentBatteryVoltage);
+ sim.setInput(u);
+ sim.update(0.020);
+ var y = sim.getOutput();
+ encoderSim.setDistance(y.get(0, 0));
+ }
+
+ assertEquals(controller.getSetpoint(), sim.getPositionMeters(), 0.2);
}
-
- assertEquals(controller.getSetpoint(), sim.getPositionMeters(), 0.2);
}
@Test
public void testMinMax() {
- var plant = LinearSystemId.createElevatorSystem(
- DCMotor.getVex775Pro(4),
- 8.0,
- 0.75 * 25.4 / 1000.0,
- 14.67);
+ var plant =
+ LinearSystemId.createElevatorSystem(
+ DCMotor.getVex775Pro(4), 8.0, 0.75 * 25.4 / 1000.0, 14.67);
- var sim = new ElevatorSim(plant,
- DCMotor.getVex775Pro(4),
- 14.67, 0.75 * 25.4 / 1000.0, 0.0, 1.0, VecBuilder.fill(0.01));
+ var sim =
+ new ElevatorSim(
+ plant,
+ DCMotor.getVex775Pro(4),
+ 14.67,
+ 0.75 * 25.4 / 1000.0,
+ 0.0,
+ 1.0,
+ VecBuilder.fill(0.01));
for (int i = 0; i < 100; i++) {
sim.setInput(VecBuilder.fill(0));
@@ -80,4 +90,20 @@
assertTrue(height <= 1.05);
}
}
+
+ @Test
+ public void testStability() {
+ var sim = new ElevatorSim(DCMotor.getVex775Pro(4), 100, 4, Units.inchesToMeters(0.5), 0, 10);
+
+ sim.setState(VecBuilder.fill(0, 0));
+ sim.setInput(12);
+ for (int i = 0; i < 50; i++) {
+ sim.update(0.02);
+ }
+
+ assertEquals(
+ sim.m_plant.calculateX(VecBuilder.fill(0, 0), VecBuilder.fill(12), 0.02 * 50.0).get(0, 0),
+ sim.getPositionMeters(),
+ 0.1);
+ }
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/EncoderSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/EncoderSimTest.java
new file mode 100644
index 0000000..931c0fe
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/EncoderSimTest.java
@@ -0,0 +1,91 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.Encoder;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.IntCallback;
+import org.junit.jupiter.api.Test;
+
+class EncoderSimTest {
+ private static final double DEFAULT_DISTANCE_PER_PULSE = 0.0005;
+
+ @Test
+ void testRate() {
+ HAL.initialize(500, 0);
+
+ try (Encoder encoder = new Encoder(0, 1)) {
+ EncoderSim sim = new EncoderSim(encoder);
+ sim.resetData();
+
+ encoder.setDistancePerPulse(DEFAULT_DISTANCE_PER_PULSE);
+
+ sim.setRate(1.91);
+ assertEquals(1.91, sim.getRate());
+ }
+ }
+
+ @Test
+ void testCount() {
+ HAL.initialize(500, 0);
+
+ try (Encoder encoder = new Encoder(0, 1)) {
+ EncoderSim sim = new EncoderSim(encoder);
+ sim.resetData();
+
+ encoder.setDistancePerPulse(DEFAULT_DISTANCE_PER_PULSE);
+
+ IntCallback callback = new IntCallback();
+ try (CallbackStore cb = sim.registerCountCallback(callback, false)) {
+ sim.setCount(3504);
+ assertEquals(3504, sim.getCount());
+
+ assertTrue(callback.wasTriggered());
+ assertEquals(3504, encoder.get());
+ assertEquals(3504, callback.getSetValue());
+ }
+ }
+ }
+
+ @Test
+ void testDistance() {
+ HAL.initialize(500, 0);
+
+ try (Encoder encoder = new Encoder(0, 1)) {
+ EncoderSim sim = new EncoderSim(encoder);
+ sim.resetData();
+
+ encoder.setDistancePerPulse(DEFAULT_DISTANCE_PER_PULSE);
+
+ sim.setDistance(229.174);
+ assertEquals(229.174, sim.getDistance());
+ assertEquals(229.174, encoder.getDistance());
+ }
+ }
+
+ @Test
+ void testPeriod() {
+ HAL.initialize(500, 0);
+
+ try (Encoder encoder = new Encoder(0, 1)) {
+ EncoderSim sim = new EncoderSim(encoder);
+ sim.resetData();
+
+ encoder.setDistancePerPulse(DEFAULT_DISTANCE_PER_PULSE);
+
+ DoubleCallback callback = new DoubleCallback();
+ try (CallbackStore cb = sim.registerPeriodCallback(callback, false)) {
+ sim.setPeriod(123.456);
+ assertEquals(123.456, sim.getPeriod());
+ assertEquals(123.456, encoder.getPeriod());
+ assertEquals(DEFAULT_DISTANCE_PER_PULSE / 123.456, encoder.getRate());
+ }
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/PWMSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/PWMSimTest.java
new file mode 100644
index 0000000..2e76aa2
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/PWMSimTest.java
@@ -0,0 +1,135 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.hal.HAL;
+import edu.wpi.first.wpilibj.PWM;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.IntCallback;
+import org.junit.jupiter.api.Test;
+
+class PWMSimTest {
+ @Test
+ void testInitialize() {
+ HAL.initialize(500, 0);
+
+ PWMSim sim = new PWMSim(0);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback callback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerInitializedCallback(callback, false);
+ PWM pwm = new PWM(0)) {
+ assertTrue(sim.getInitialized());
+ }
+ }
+
+ @Test
+ void testSetRawValue() {
+ HAL.initialize(500, 0);
+
+ PWMSim sim = new PWMSim(0);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ IntCallback callback = new IntCallback();
+
+ try (CallbackStore cb = sim.registerRawValueCallback(callback, false);
+ PWM pwm = new PWM(0)) {
+ sim.setRawValue(229);
+ assertEquals(229, sim.getRawValue());
+ assertEquals(229, pwm.getRaw());
+ assertTrue(callback.wasTriggered());
+ assertEquals(229, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetSpeed() {
+ HAL.initialize(500, 0);
+
+ PWMSim sim = new PWMSim(0);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ DoubleCallback callback = new DoubleCallback();
+
+ try (CallbackStore cb = sim.registerSpeedCallback(callback, false);
+ PWM pwm = new PWM(0)) {
+ final double kTestValue = 0.3504;
+ pwm.setSpeed(kTestValue);
+
+ assertEquals(kTestValue, sim.getSpeed());
+ assertEquals(kTestValue, pwm.getSpeed());
+ assertTrue(callback.wasTriggered());
+ assertEquals(kTestValue, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetPosition() {
+ HAL.initialize(500, 0);
+
+ PWMSim sim = new PWMSim(0);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ DoubleCallback callback = new DoubleCallback();
+
+ try (CallbackStore cb = sim.registerPositionCallback(callback, false);
+ PWM pwm = new PWM(0)) {
+ final double kTestValue = 0.3504;
+ pwm.setPosition(kTestValue);
+
+ assertEquals(kTestValue, sim.getPosition());
+ assertEquals(kTestValue, pwm.getPosition());
+ assertTrue(callback.wasTriggered());
+ assertEquals(kTestValue, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetPeriodScale() {
+ HAL.initialize(500, 0);
+
+ PWMSim sim = new PWMSim(0);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ IntCallback callback = new IntCallback();
+
+ try (CallbackStore cb = sim.registerPeriodScaleCallback(callback, false);
+ PWM pwm = new PWM(0)) {
+ sim.setPeriodScale(3504);
+ assertEquals(3504, sim.getPeriodScale());
+ assertTrue(callback.wasTriggered());
+ assertEquals(3504, callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetZeroLatch() {
+ HAL.initialize(500, 0);
+
+ PWMSim sim = new PWMSim(0);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback callback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerZeroLatchCallback(callback, false);
+ PWM pwm = new PWM(0)) {
+ pwm.setZeroLatch();
+
+ assertTrue(callback.wasTriggered());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/REVPHSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/REVPHSimTest.java
new file mode 100644
index 0000000..8bdf23e
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/REVPHSimTest.java
@@ -0,0 +1,168 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.DoubleSolenoid;
+import edu.wpi.first.wpilibj.PneumaticHub;
+import edu.wpi.first.wpilibj.PneumaticsModuleType;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import org.junit.jupiter.api.Test;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+class REVPHSimTest {
+ @Test
+ void testInitialization() {
+ HAL.initialize(500, 0);
+
+ REVPHSim sim = new REVPHSim(1);
+ sim.resetData();
+ assertFalse(sim.getInitialized());
+
+ BooleanCallback callback = new BooleanCallback();
+
+ try (CallbackStore cb = sim.registerInitializedCallback(callback, false);
+ PneumaticHub ph = new PneumaticHub(1)) {
+ assertTrue(sim.getInitialized());
+ }
+ assertFalse(sim.getInitialized());
+ }
+
+ @Test
+ void solenoidOutputTest() {
+ HAL.initialize(500, 0);
+
+ try (PneumaticHub ph = new PneumaticHub(1);
+ DoubleSolenoid doubleSolenoid = new DoubleSolenoid(1, PneumaticsModuleType.REVPH, 3, 4)) {
+ REVPHSim sim = new REVPHSim(ph);
+ sim.resetData();
+
+ BooleanCallback callback3 = new BooleanCallback();
+ BooleanCallback callback4 = new BooleanCallback();
+
+ try (CallbackStore cb3 = sim.registerSolenoidOutputCallback(3, callback3, false);
+ CallbackStore cb4 = sim.registerSolenoidOutputCallback(4, callback4, false)) {
+ // Reverse
+ callback3.reset();
+ callback4.reset();
+ doubleSolenoid.set(DoubleSolenoid.Value.kReverse);
+ assertFalse(callback3.wasTriggered());
+ assertNull(callback3.getSetValue());
+ assertTrue(callback4.wasTriggered());
+ assertTrue(callback4.getSetValue());
+ assertFalse(sim.getSolenoidOutput(3));
+ assertTrue(sim.getSolenoidOutput(4));
+ assertEquals(0x10, ph.getSolenoids());
+
+ // Forward
+ callback3.reset();
+ callback4.reset();
+ doubleSolenoid.set(DoubleSolenoid.Value.kForward);
+ assertTrue(callback3.wasTriggered());
+ assertTrue(callback3.getSetValue());
+ assertTrue(callback4.wasTriggered());
+ assertFalse(callback4.getSetValue());
+ assertTrue(sim.getSolenoidOutput(3));
+ assertFalse(sim.getSolenoidOutput(4));
+ assertEquals(0x8, ph.getSolenoids());
+
+ // Off
+ callback3.reset();
+ callback4.reset();
+ doubleSolenoid.set(DoubleSolenoid.Value.kOff);
+ assertTrue(callback3.wasTriggered());
+ assertFalse(callback3.getSetValue());
+ assertFalse(callback4.wasTriggered());
+ assertNull(callback4.getSetValue());
+ assertFalse(sim.getSolenoidOutput(3));
+ assertFalse(sim.getSolenoidOutput(4));
+ assertEquals(0x0, ph.getSolenoids());
+ }
+ }
+ }
+
+ @Test
+ void setCompressorOnTest() {
+ HAL.initialize(500, 0);
+
+ REVPHSim sim = new REVPHSim(1);
+ BooleanCallback callback = new BooleanCallback();
+
+ try (PneumaticHub ph = new PneumaticHub(1);
+ CallbackStore cb = sim.registerCompressorOnCallback(callback, false)) {
+ assertFalse(ph.getCompressor());
+ assertFalse(sim.getCompressorOn());
+ sim.setCompressorOn(true);
+ assertTrue(ph.getCompressor());
+ assertTrue(sim.getCompressorOn());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void setClosedLoopEnabled() {
+ HAL.initialize(500, 0);
+
+ REVPHSim sim = new REVPHSim(1);
+ BooleanCallback callback = new BooleanCallback();
+
+ try (PneumaticHub ph = new PneumaticHub(1);
+ CallbackStore cb = sim.registerClosedLoopEnabledCallback(callback, false)) {
+ ph.setClosedLoopControl(false);
+ assertFalse(ph.getClosedLoopControl());
+
+ ph.setClosedLoopControl(true);
+ assertTrue(sim.getClosedLoopEnabled());
+ assertTrue(ph.getClosedLoopControl());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void setPressureSwitchEnabledTest() {
+ HAL.initialize(500, 0);
+
+ REVPHSim sim = new REVPHSim(1);
+ BooleanCallback callback = new BooleanCallback();
+
+ try (PneumaticHub ph = new PneumaticHub(1);
+ CallbackStore cb = sim.registerPressureSwitchCallback(callback, false)) {
+ assertFalse(ph.getPressureSwitch());
+
+ sim.setPressureSwitch(true);
+ assertTrue(sim.getPressureSwitch());
+ assertTrue(ph.getPressureSwitch());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void setCompressorCurrentTest() {
+ HAL.initialize(500, 0);
+
+ REVPHSim sim = new REVPHSim(1);
+ DoubleCallback callback = new DoubleCallback();
+
+ try (PneumaticHub ph = new PneumaticHub(1);
+ CallbackStore cb = sim.registerCompressorCurrentCallback(callback, false)) {
+ assertFalse(ph.getPressureSwitch());
+
+ sim.setCompressorCurrent(35.04);
+ assertEquals(35.04, sim.getCompressorCurrent());
+ assertEquals(35.04, ph.getCompressorCurrent());
+ assertTrue(callback.wasTriggered());
+ assertEquals(35.04, callback.getSetValue());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RelaySimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RelaySimTest.java
new file mode 100644
index 0000000..ba84fc5
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RelaySimTest.java
@@ -0,0 +1,258 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import edu.wpi.first.hal.HAL;
+import edu.wpi.first.wpilibj.Relay;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import org.junit.jupiter.api.Test;
+
+class RelaySimTest {
+ @Test
+ void testInitializationBidrectional() {
+ HAL.initialize(500, 0);
+
+ RelaySim sim = new RelaySim(0);
+ sim.resetData();
+
+ BooleanCallback forwardCallback = new BooleanCallback();
+ BooleanCallback reverseCallback = new BooleanCallback();
+
+ assertFalse(sim.getInitializedForward());
+ assertFalse(sim.getInitializedReverse());
+
+ try (CallbackStore fwdCb = sim.registerInitializedForwardCallback(forwardCallback, false);
+ CallbackStore revCb = sim.registerInitializedReverseCallback(reverseCallback, false);
+ Relay relay = new Relay(0)) {
+ assertTrue(sim.getInitializedForward());
+ assertTrue(sim.getInitializedReverse());
+
+ assertTrue(forwardCallback.wasTriggered());
+ assertTrue(forwardCallback.getSetValue());
+ assertTrue(reverseCallback.wasTriggered());
+ assertTrue(reverseCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testInitializationForwardOnly() {
+ HAL.initialize(500, 0);
+
+ RelaySim sim = new RelaySim(0);
+ sim.resetData();
+
+ BooleanCallback forwardCallback = new BooleanCallback();
+ BooleanCallback reverseCallback = new BooleanCallback();
+
+ assertFalse(sim.getInitializedForward());
+ assertFalse(sim.getInitializedReverse());
+
+ try (CallbackStore fwdCb = sim.registerInitializedForwardCallback(forwardCallback, false);
+ CallbackStore revCb = sim.registerInitializedReverseCallback(reverseCallback, false);
+ Relay relay = new Relay(0, Relay.Direction.kForward); ) {
+ assertTrue(sim.getInitializedForward());
+ assertFalse(sim.getInitializedReverse());
+
+ assertTrue(forwardCallback.wasTriggered());
+ assertTrue(forwardCallback.getSetValue());
+ assertFalse(reverseCallback.wasTriggered());
+ assertNull(reverseCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testInitializationReverseOnly() {
+ HAL.initialize(500, 0);
+
+ RelaySim sim = new RelaySim(0);
+ sim.resetData();
+
+ BooleanCallback forwardCallback = new BooleanCallback();
+ BooleanCallback reverseCallback = new BooleanCallback();
+
+ assertFalse(sim.getInitializedForward());
+ assertFalse(sim.getInitializedReverse());
+
+ try (CallbackStore fwdCb = sim.registerInitializedForwardCallback(forwardCallback, false);
+ CallbackStore revCb = sim.registerInitializedReverseCallback(reverseCallback, false);
+ Relay relay = new Relay(0, Relay.Direction.kReverse); ) {
+ assertFalse(sim.getInitializedForward());
+ assertTrue(sim.getInitializedReverse());
+
+ assertFalse(forwardCallback.wasTriggered());
+ assertNull(forwardCallback.getSetValue());
+ assertTrue(reverseCallback.wasTriggered());
+ assertTrue(reverseCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testBidirectionalSetForward() {
+ HAL.initialize(500, 0);
+
+ RelaySim sim = new RelaySim(0);
+ BooleanCallback forwardCallback = new BooleanCallback();
+ BooleanCallback reverseCallback = new BooleanCallback();
+
+ try (Relay relay = new Relay(0);
+ CallbackStore fwdCb = sim.registerForwardCallback(forwardCallback, false);
+ CallbackStore revCb = sim.registerReverseCallback(reverseCallback, false)) {
+ relay.set(Relay.Value.kForward);
+ assertEquals(Relay.Value.kForward, relay.get());
+ assertTrue(sim.getForward());
+ assertFalse(sim.getReverse());
+
+ assertTrue(forwardCallback.wasTriggered());
+ assertTrue(forwardCallback.getSetValue());
+ assertFalse(reverseCallback.wasTriggered());
+ assertNull(reverseCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testBidirectionalSetReverse() {
+ HAL.initialize(500, 0);
+
+ RelaySim sim = new RelaySim(0);
+ BooleanCallback forwardCallback = new BooleanCallback();
+ BooleanCallback reverseCallback = new BooleanCallback();
+
+ try (Relay relay = new Relay(0);
+ CallbackStore fwdCb = sim.registerForwardCallback(forwardCallback, false);
+ CallbackStore revCb = sim.registerReverseCallback(reverseCallback, false)) {
+ relay.set(Relay.Value.kReverse);
+ assertEquals(Relay.Value.kReverse, relay.get());
+ assertFalse(sim.getForward());
+ assertTrue(sim.getReverse());
+
+ assertFalse(forwardCallback.wasTriggered());
+ assertNull(forwardCallback.getSetValue());
+ assertTrue(reverseCallback.wasTriggered());
+ assertTrue(reverseCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testBidirectionalSetOn() {
+ HAL.initialize(500, 0);
+
+ RelaySim sim = new RelaySim(0);
+ BooleanCallback forwardCallback = new BooleanCallback();
+ BooleanCallback reverseCallback = new BooleanCallback();
+
+ try (Relay relay = new Relay(0);
+ CallbackStore fwdCb = sim.registerForwardCallback(forwardCallback, false);
+ CallbackStore revCb = sim.registerReverseCallback(reverseCallback, false)) {
+ relay.set(Relay.Value.kOn);
+ assertEquals(Relay.Value.kOn, relay.get());
+ assertTrue(sim.getForward());
+ assertTrue(sim.getReverse());
+
+ assertTrue(forwardCallback.wasTriggered());
+ assertTrue(forwardCallback.getSetValue());
+ assertTrue(reverseCallback.wasTriggered());
+ assertTrue(reverseCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testBidirectionalSetOff() {
+ HAL.initialize(500, 0);
+
+ RelaySim sim = new RelaySim(0);
+ BooleanCallback forwardCallback = new BooleanCallback();
+ BooleanCallback reverseCallback = new BooleanCallback();
+
+ try (Relay relay = new Relay(0);
+ CallbackStore fwdCb = sim.registerForwardCallback(forwardCallback, false);
+ CallbackStore revCb = sim.registerReverseCallback(reverseCallback, false)) {
+ // Bootstrap into a non-off state to verify the callbacks
+ relay.set(Relay.Value.kOn);
+ forwardCallback.reset();
+ reverseCallback.reset();
+
+ relay.set(Relay.Value.kOff);
+ assertEquals(Relay.Value.kOff, relay.get());
+ assertFalse(sim.getForward());
+ assertFalse(sim.getReverse());
+
+ assertTrue(forwardCallback.wasTriggered());
+ assertFalse(forwardCallback.getSetValue());
+ assertTrue(reverseCallback.wasTriggered());
+ assertFalse(reverseCallback.getSetValue());
+ }
+ }
+
+ @Test
+ void testStopMotor() {
+ try (Relay relay = new Relay(0)) {
+ // Bootstrap into non-off state
+ relay.set(Relay.Value.kOn);
+
+ relay.stopMotor();
+ assertEquals(Relay.Value.kOff, relay.get());
+ }
+ }
+
+ @Test
+ void testForwardOnlyCannotGoReverse() {
+ try (Relay relay = new Relay(0, Relay.Direction.kForward)) {
+ relay.set(Relay.Value.kForward);
+ assertEquals(Relay.Value.kOn, relay.get());
+
+ relay.set(Relay.Value.kOff);
+ assertEquals(Relay.Value.kOff, relay.get());
+
+ assertThrows(Relay.InvalidValueException.class, () -> relay.set(Relay.Value.kReverse));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kOn));
+ }
+ }
+
+ @Test
+ void testReverseOnlyCannotGoForwards() {
+ try (Relay relay = new Relay(0, Relay.Direction.kReverse)) {
+ relay.set(Relay.Value.kReverse);
+ assertEquals(Relay.Value.kOn, relay.get());
+
+ relay.set(Relay.Value.kOff);
+ assertEquals(Relay.Value.kOff, relay.get());
+
+ assertThrows(Relay.InvalidValueException.class, () -> relay.set(Relay.Value.kForward));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kOn));
+ }
+ }
+
+ @Test
+ void testSwitchDirections() {
+ try (Relay relay = new Relay(0, Relay.Direction.kBoth)) {
+ // Start with both. Should be able to set all 4 values
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kOff));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kForward));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kReverse));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kOn));
+
+ // Switch it to forward only
+ relay.setDirection(Relay.Direction.kForward);
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kOff));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kForward));
+ assertThrows(Relay.InvalidValueException.class, () -> relay.set(Relay.Value.kReverse));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kOn));
+
+ // Switch it to Reverse only
+ relay.setDirection(Relay.Direction.kReverse);
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kOff));
+ assertThrows(Relay.InvalidValueException.class, () -> relay.set(Relay.Value.kForward));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kReverse));
+ assertDoesNotThrow(() -> relay.set(Relay.Value.kOn));
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RoboRioSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RoboRioSimTest.java
new file mode 100644
index 0000000..e9ea9f1
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RoboRioSimTest.java
@@ -0,0 +1,211 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation;
+
+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.hal.HALUtil;
+import edu.wpi.first.wpilibj.RobotController;
+import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
+import edu.wpi.first.wpilibj.simulation.testutils.IntCallback;
+import org.junit.jupiter.api.Test;
+
+public class RoboRioSimTest {
+ @Test
+ void testFPGAButton() {
+ RoboRioSim.resetData();
+
+ BooleanCallback callback = new BooleanCallback();
+ try (CallbackStore cb = RoboRioSim.registerFPGAButtonCallback(callback, false)) {
+ RoboRioSim.setFPGAButton(true);
+ assertTrue(RoboRioSim.getFPGAButton());
+ assertTrue(HALUtil.getFPGAButton());
+ assertTrue(callback.wasTriggered());
+ assertTrue(callback.getSetValue());
+
+ callback.reset();
+ RoboRioSim.setFPGAButton(false);
+ assertFalse(RoboRioSim.getFPGAButton());
+ assertFalse(HALUtil.getFPGAButton());
+ assertTrue(callback.wasTriggered());
+ assertFalse(callback.getSetValue());
+ }
+ }
+
+ @Test
+ void testSetVin() {
+ RoboRioSim.resetData();
+
+ DoubleCallback voltageCallback = new DoubleCallback();
+ DoubleCallback currentCallback = new DoubleCallback();
+ try (CallbackStore voltageCb = RoboRioSim.registerVInVoltageCallback(voltageCallback, false);
+ CallbackStore currentCb = RoboRioSim.registerVInCurrentCallback(currentCallback, false)) {
+ final double kTestVoltage = 1.91;
+ final double kTestCurrent = 35.04;
+
+ RoboRioSim.setVInVoltage(kTestVoltage);
+ assertTrue(voltageCallback.wasTriggered());
+ assertEquals(kTestVoltage, voltageCallback.getSetValue());
+ assertEquals(kTestVoltage, RoboRioSim.getVInVoltage());
+ assertEquals(kTestVoltage, RobotController.getInputVoltage());
+
+ RoboRioSim.setVInCurrent(kTestCurrent);
+ assertTrue(currentCallback.wasTriggered());
+ assertEquals(kTestCurrent, currentCallback.getSetValue());
+ assertEquals(kTestCurrent, RoboRioSim.getVInCurrent());
+ assertEquals(kTestCurrent, RobotController.getInputCurrent());
+ }
+ }
+
+ @Test
+ void testSetBrownout() {
+ RoboRioSim.resetData();
+
+ DoubleCallback voltageCallback = new DoubleCallback();
+ try (CallbackStore voltageCb =
+ RoboRioSim.registerBrownoutVoltageCallback(voltageCallback, false)) {
+ final double kTestVoltage = 1.91;
+
+ RoboRioSim.setBrownoutVoltage(kTestVoltage);
+ assertTrue(voltageCallback.wasTriggered());
+ assertEquals(kTestVoltage, voltageCallback.getSetValue());
+ assertEquals(kTestVoltage, RoboRioSim.getBrownoutVoltage());
+ assertEquals(kTestVoltage, RobotController.getBrownoutVoltage());
+ }
+ }
+
+ @Test
+ void test6V() {
+ RoboRioSim.resetData();
+
+ DoubleCallback voltageCallback = new DoubleCallback();
+ DoubleCallback currentCallback = new DoubleCallback();
+ BooleanCallback activeCallback = new BooleanCallback();
+ IntCallback faultCallback = new IntCallback();
+ try (CallbackStore voltageCb =
+ RoboRioSim.registerUserVoltage6VCallback(voltageCallback, false);
+ CallbackStore currentCb = RoboRioSim.registerUserCurrent6VCallback(currentCallback, false);
+ CallbackStore activeCb = RoboRioSim.registerUserActive6VCallback(activeCallback, false);
+ CallbackStore faultsCb = RoboRioSim.registerUserFaults6VCallback(faultCallback, false)) {
+ final double kTestVoltage = 22.9;
+ final double kTestCurrent = 174;
+ final int kTestFaults = 229;
+
+ RoboRioSim.setUserVoltage6V(kTestVoltage);
+ assertTrue(voltageCallback.wasTriggered());
+ assertEquals(kTestVoltage, voltageCallback.getSetValue());
+ assertEquals(kTestVoltage, RoboRioSim.getUserVoltage6V());
+ assertEquals(kTestVoltage, RobotController.getVoltage6V());
+
+ RoboRioSim.setUserCurrent6V(kTestCurrent);
+ assertTrue(currentCallback.wasTriggered());
+ assertEquals(kTestCurrent, currentCallback.getSetValue());
+ assertEquals(kTestCurrent, RoboRioSim.getUserCurrent6V());
+ assertEquals(kTestCurrent, RobotController.getCurrent6V());
+
+ RoboRioSim.setUserActive6V(false);
+ assertTrue(activeCallback.wasTriggered());
+ assertFalse(activeCallback.getSetValue());
+ assertFalse(RoboRioSim.getUserActive6V());
+ assertFalse(RobotController.getEnabled6V());
+
+ RoboRioSim.setUserFaults6V(kTestFaults);
+ assertTrue(faultCallback.wasTriggered());
+ assertEquals(kTestFaults, faultCallback.getSetValue());
+ assertEquals(kTestFaults, RoboRioSim.getUserFaults6V());
+ assertEquals(kTestFaults, RobotController.getFaultCount6V());
+ }
+ }
+
+ @Test
+ void test5V() {
+ RoboRioSim.resetData();
+
+ DoubleCallback voltageCallback = new DoubleCallback();
+ DoubleCallback currentCallback = new DoubleCallback();
+ BooleanCallback activeCallback = new BooleanCallback();
+ IntCallback faultCallback = new IntCallback();
+ try (CallbackStore voltageCb =
+ RoboRioSim.registerUserVoltage5VCallback(voltageCallback, false);
+ CallbackStore currentCb = RoboRioSim.registerUserCurrent5VCallback(currentCallback, false);
+ CallbackStore activeCb = RoboRioSim.registerUserActive5VCallback(activeCallback, false);
+ CallbackStore faultsCb = RoboRioSim.registerUserFaults5VCallback(faultCallback, false)) {
+ final double kTestVoltage = 22.9;
+ final double kTestCurrent = 174;
+ final int kTestFaults = 229;
+
+ RoboRioSim.setUserVoltage5V(kTestVoltage);
+ assertTrue(voltageCallback.wasTriggered());
+ assertEquals(kTestVoltage, voltageCallback.getSetValue());
+ assertEquals(kTestVoltage, RoboRioSim.getUserVoltage5V());
+ assertEquals(kTestVoltage, RobotController.getVoltage5V());
+
+ RoboRioSim.setUserCurrent5V(kTestCurrent);
+ assertTrue(currentCallback.wasTriggered());
+ assertEquals(kTestCurrent, currentCallback.getSetValue());
+ assertEquals(kTestCurrent, RoboRioSim.getUserCurrent5V());
+ assertEquals(kTestCurrent, RobotController.getCurrent5V());
+
+ RoboRioSim.setUserActive5V(false);
+ assertTrue(activeCallback.wasTriggered());
+ assertFalse(activeCallback.getSetValue());
+ assertFalse(RoboRioSim.getUserActive5V());
+ assertFalse(RobotController.getEnabled5V());
+
+ RoboRioSim.setUserFaults5V(kTestFaults);
+ assertTrue(faultCallback.wasTriggered());
+ assertEquals(kTestFaults, faultCallback.getSetValue());
+ assertEquals(kTestFaults, RoboRioSim.getUserFaults5V());
+ assertEquals(kTestFaults, RobotController.getFaultCount5V());
+ }
+ }
+
+ @Test
+ void test3V3() {
+ RoboRioSim.resetData();
+
+ DoubleCallback voltageCallback = new DoubleCallback();
+ DoubleCallback currentCallback = new DoubleCallback();
+ BooleanCallback activeCallback = new BooleanCallback();
+ IntCallback faultCallback = new IntCallback();
+ try (CallbackStore voltageCb =
+ RoboRioSim.registerUserVoltage3V3Callback(voltageCallback, false);
+ CallbackStore currentCb =
+ RoboRioSim.registerUserCurrent3V3Callback(currentCallback, false);
+ CallbackStore activeCb = RoboRioSim.registerUserActive3V3Callback(activeCallback, false);
+ CallbackStore faultsCb = RoboRioSim.registerUserFaults3V3Callback(faultCallback, false)) {
+ final double kTestVoltage = 22.9;
+ final double kTestCurrent = 174;
+ final int kTestFaults = 229;
+
+ RoboRioSim.setUserVoltage3V3(kTestVoltage);
+ assertTrue(voltageCallback.wasTriggered());
+ assertEquals(kTestVoltage, voltageCallback.getSetValue());
+ assertEquals(kTestVoltage, RoboRioSim.getUserVoltage3V3());
+ assertEquals(kTestVoltage, RobotController.getVoltage3V3());
+
+ RoboRioSim.setUserCurrent3V3(kTestCurrent);
+ assertTrue(currentCallback.wasTriggered());
+ assertEquals(kTestCurrent, currentCallback.getSetValue());
+ assertEquals(kTestCurrent, RoboRioSim.getUserCurrent3V3());
+ assertEquals(kTestCurrent, RobotController.getCurrent3V3());
+
+ RoboRioSim.setUserActive3V3(false);
+ assertTrue(activeCallback.wasTriggered());
+ assertFalse(activeCallback.getSetValue());
+ assertFalse(RoboRioSim.getUserActive3V3());
+ assertFalse(RobotController.getEnabled3V3());
+
+ RoboRioSim.setUserFaults3V3(kTestFaults);
+ assertTrue(faultCallback.wasTriggered());
+ assertEquals(kTestFaults, faultCallback.getSetValue());
+ assertEquals(kTestFaults, RoboRioSim.getUserFaults3V3());
+ assertEquals(kTestFaults, RobotController.getFaultCount3V3());
+ }
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/SimDeviceSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/SimDeviceSimTest.java
index 6b9fe61..1daea96 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/SimDeviceSimTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/SimDeviceSimTest.java
@@ -1,31 +1,178 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import org.junit.jupiter.api.Test;
+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.hal.SimBoolean;
import edu.wpi.first.hal.SimDevice;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import edu.wpi.first.hal.SimDevice.Direction;
+import edu.wpi.first.hal.SimValue;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.jupiter.api.Test;
class SimDeviceSimTest {
@Test
void testBasic() {
- SimDevice dev = SimDevice.create("test");
- SimBoolean devBool = dev.createBoolean("bool", false, false);
+ try (SimDevice dev = SimDevice.create("test")) {
+ SimBoolean devBool = dev.createBoolean("bool", Direction.kBidir, false);
- SimDeviceSim sim = new SimDeviceSim("test");
- SimBoolean simBool = sim.getBoolean("bool");
+ SimDeviceSim sim = new SimDeviceSim("test");
+ SimBoolean simBool = sim.getBoolean("bool");
- assertFalse(simBool.get());
- simBool.set(true);
- assertTrue(devBool.get());
+ assertFalse(simBool.get());
+ simBool.set(true);
+ assertTrue(devBool.get());
+ }
+ }
+
+ @Test
+ void testDeviceCreatedCallback() {
+ AtomicInteger callback1Counter = new AtomicInteger(0);
+ AtomicInteger callback2Counter = new AtomicInteger(0);
+
+ try (SimDevice otherdev = SimDevice.create("testnotDC");
+ SimDevice dev1 = SimDevice.create("testDC1")) {
+ try (CallbackStore callback1 =
+ SimDeviceSim.registerDeviceCreatedCallback(
+ "testDC",
+ (name, handle) -> {
+ callback1Counter.addAndGet(1);
+ },
+ false);
+ CallbackStore callback2 =
+ SimDeviceSim.registerDeviceCreatedCallback(
+ "testDC",
+ (name, handle) -> {
+ callback2Counter.addAndGet(1);
+ },
+ true)) {
+ assertEquals(0, callback1Counter.get(), "Callback 1 called early");
+ assertEquals(
+ 1,
+ callback2Counter.get(),
+ "Callback 2 called early or not initialized with existing devices");
+
+ SimDevice dev2 = SimDevice.create("testDC2");
+ dev2.close();
+
+ assertEquals(
+ 1, callback1Counter.get(), "Callback 1 called either more than once or not at all");
+ assertEquals(2, callback2Counter.get(), "Callback 2 called either more or less than twice");
+ }
+
+ SimDevice dev3 = SimDevice.create("testDC3");
+ dev3.close();
+
+ assertEquals(1, callback1Counter.get(), "Callback 1 called after closure");
+ assertEquals(2, callback2Counter.get(), "Callback 2 called after closure");
+ }
+ }
+
+ @Test
+ void testDeviceFreedCallback() {
+ AtomicInteger counter = new AtomicInteger(0);
+
+ SimDevice dev1 = SimDevice.create("testDF1");
+ try (CallbackStore callback =
+ SimDeviceSim.registerDeviceFreedCallback(
+ "testDF",
+ (name, handle) -> {
+ counter.addAndGet(1);
+ },
+ false)) {
+ assertEquals(0, counter.get(), "Callback called early");
+ dev1.close();
+ assertEquals(1, counter.get(), "Callback called either more than once or not at all");
+ }
+
+ SimDevice dev2 = SimDevice.create("testDF2");
+ dev2.close();
+
+ assertEquals(1, counter.get(), "Callback called after closure");
+ }
+
+ @Test
+ void testValueCreatedCallback() {
+ AtomicInteger callback1Counter = new AtomicInteger(0);
+ AtomicInteger callback2Counter = new AtomicInteger(0);
+
+ try (SimDevice dev1 = SimDevice.create("testVM1")) {
+ dev1.createBoolean("v1", Direction.kBidir, false);
+ SimDeviceSim sim = new SimDeviceSim("testVM1");
+ try (CallbackStore callback1 =
+ sim.registerValueCreatedCallback(
+ (name, handle, readonly, value) -> {
+ callback1Counter.addAndGet(1);
+ },
+ false);
+ CallbackStore callback2 =
+ sim.registerValueCreatedCallback(
+ (name, handle, readonly, value) -> {
+ callback2Counter.addAndGet(1);
+ },
+ true)) {
+ assertEquals(0, callback1Counter.get(), "Callback 1 called early");
+ assertEquals(
+ 1,
+ callback2Counter.get(),
+ "Callback 2 called early or not initialized with existing devices");
+
+ dev1.createDouble("v2", Direction.kBidir, 0);
+
+ assertEquals(
+ 1, callback1Counter.get(), "Callback 1 called either more than once or not at all");
+ assertEquals(2, callback2Counter.get(), "Callback 2 called either more or less than twice");
+ }
+ dev1.createBoolean("v3", Direction.kBidir, false);
+
+ assertEquals(1, callback1Counter.get(), "Callback 1 called after closure");
+ assertEquals(2, callback2Counter.get(), "Callback 2 called after closure");
+ }
+ }
+
+ @Test
+ void testValueChangedCallback() {
+ AtomicInteger callback1Counter = new AtomicInteger(0);
+ AtomicInteger callback2Counter = new AtomicInteger(0);
+
+ try (SimDevice dev1 = SimDevice.create("testVM1")) {
+ SimBoolean val = dev1.createBoolean("v1", Direction.kBidir, false);
+ SimDeviceSim sim = new SimDeviceSim("testVM1");
+ SimValue simVal = sim.getValue("v1");
+ try (CallbackStore callback1 =
+ sim.registerValueChangedCallback(
+ simVal,
+ (name, handle, readonly, value) -> {
+ callback1Counter.addAndGet(1);
+ },
+ false);
+ CallbackStore callback2 =
+ sim.registerValueChangedCallback(
+ simVal,
+ (name, handle, readonly, value) -> {
+ callback2Counter.addAndGet(1);
+ },
+ true)) {
+ assertEquals(0, callback1Counter.get(), "Callback 1 called early");
+ assertEquals(
+ 1,
+ callback2Counter.get(),
+ "Callback 2 called early or not initialized with existing devices");
+
+ val.set(true);
+
+ assertEquals(
+ 1, callback1Counter.get(), "Callback 1 called either more than once or not at all");
+ assertEquals(2, callback2Counter.get(), "Callback 2 called either more or less than twice");
+ }
+ val.set(false);
+ assertEquals(1, callback1Counter.get(), "Callback 1 called after closure");
+ assertEquals(2, callback2Counter.get(), "Callback 2 called after closure");
+ }
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/SingleJointedArmSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/SingleJointedArmSimTest.java
index f1b4bc8..26aa6b9 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/SingleJointedArmSimTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/SingleJointedArmSimTest.java
@@ -1,28 +1,27 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.simulation;
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.wpilibj.system.plant.DCMotor;
-import edu.wpi.first.wpilibj.util.Units;
-import edu.wpi.first.wpiutil.math.VecBuilder;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
+import edu.wpi.first.math.VecBuilder;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.math.util.Units;
+import org.junit.jupiter.api.Test;
+
public class SingleJointedArmSimTest {
- SingleJointedArmSim m_sim = new SingleJointedArmSim(
- DCMotor.getVex775Pro(2),
- 100,
- 3.0,
- Units.inchesToMeters(19.0 / 2.0),
- -Math.PI,
- 0.0, 10.0 / 2.2, true);
+ SingleJointedArmSim m_sim =
+ new SingleJointedArmSim(
+ DCMotor.getVex775Pro(2),
+ 100,
+ 3.0,
+ Units.inchesToMeters(19.0 / 2.0),
+ -Math.PI,
+ 0.0,
+ 10.0 / 2.2,
+ true);
@Test
public void testArmDisabled() {
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/BooleanCallback.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/BooleanCallback.java
new file mode 100644
index 0000000..f368d7f
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/BooleanCallback.java
@@ -0,0 +1,19 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation.testutils;
+
+import edu.wpi.first.hal.HALValue;
+
+public class BooleanCallback extends CallbackHelperBase<Boolean> {
+ @Override
+ public void callback(String name, HALValue value) {
+ if (value.getType() != HALValue.kBoolean) {
+ throw new IllegalArgumentException("Wrong callback for type " + value.getType());
+ }
+
+ m_wasTriggered = true;
+ m_setValue = value.getBoolean();
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/BufferCallback.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/BufferCallback.java
new file mode 100644
index 0000000..fdd8c06
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/BufferCallback.java
@@ -0,0 +1,27 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation.testutils;
+
+import edu.wpi.first.hal.simulation.ConstBufferCallback;
+import java.util.Arrays;
+
+public class BufferCallback implements ConstBufferCallback {
+ private boolean m_wasTriggered;
+ private byte[] m_setValue;
+
+ @Override
+ public void callback(String name, byte[] buffer, int count) {
+ m_wasTriggered = true;
+ m_setValue = Arrays.copyOf(buffer, buffer.length);
+ }
+
+ public boolean wasTriggered() {
+ return m_wasTriggered;
+ }
+
+ public byte[] getSetValue() {
+ return Arrays.copyOf(m_setValue, m_setValue.length);
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/CallbackHelperBase.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/CallbackHelperBase.java
new file mode 100644
index 0000000..4fb455e
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/CallbackHelperBase.java
@@ -0,0 +1,25 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation.testutils;
+
+import edu.wpi.first.hal.simulation.NotifyCallback;
+
+public abstract class CallbackHelperBase<T> implements NotifyCallback {
+ protected boolean m_wasTriggered;
+ protected T m_setValue;
+
+ public final boolean wasTriggered() {
+ return m_wasTriggered;
+ }
+
+ public final T getSetValue() {
+ return m_setValue;
+ }
+
+ public final void reset() {
+ m_wasTriggered = false;
+ m_setValue = null;
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/DoubleCallback.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/DoubleCallback.java
new file mode 100644
index 0000000..ccf53f3
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/DoubleCallback.java
@@ -0,0 +1,19 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation.testutils;
+
+import edu.wpi.first.hal.HALValue;
+
+public class DoubleCallback extends CallbackHelperBase<Double> {
+ @Override
+ public void callback(String name, HALValue value) {
+ if (value.getType() != HALValue.kDouble) {
+ throw new IllegalArgumentException("Wrong callback for type " + value.getType());
+ }
+
+ m_wasTriggered = true;
+ m_setValue = value.getDouble();
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/EnumCallback.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/EnumCallback.java
new file mode 100644
index 0000000..2c585ac
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/EnumCallback.java
@@ -0,0 +1,19 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation.testutils;
+
+import edu.wpi.first.hal.HALValue;
+
+public class EnumCallback extends CallbackHelperBase<Long> {
+ @Override
+ public void callback(String name, HALValue value) {
+ if (value.getType() != HALValue.kEnum) {
+ throw new IllegalArgumentException("Wrong callback for type " + value.getType());
+ }
+
+ m_wasTriggered = true;
+ m_setValue = value.getLong();
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/IntCallback.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/IntCallback.java
new file mode 100644
index 0000000..a1f65c4
--- /dev/null
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/testutils/IntCallback.java
@@ -0,0 +1,19 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.wpilibj.simulation.testutils;
+
+import edu.wpi.first.hal.HALValue;
+
+public class IntCallback extends CallbackHelperBase<Integer> {
+ @Override
+ public void callback(String name, HALValue value) {
+ if (value.getType() != HALValue.kInt) {
+ throw new IllegalArgumentException("Wrong callback for type " + value.getType());
+ }
+
+ m_wasTriggered = true;
+ m_setValue = (int) value.getLong();
+ }
+}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboardTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboardTest.java
index cc92ed0..dfefddb 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboardTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/smartdashboard/SmartDashboardTest.java
@@ -1,21 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj.smartdashboard;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.UtilityClassTest;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
class SmartDashboardTest extends UtilityClassTest<SmartDashboard> {
private final NetworkTable m_table = NetworkTableInstance.getDefault().getTable("SmartDashboard");
@@ -107,13 +103,14 @@
@Test
void putStringNullKeyTest() {
- assertThrows(NullPointerException.class,
- () -> SmartDashboard.putString(null, "This should not work"));
+ assertThrows(
+ NullPointerException.class, () -> SmartDashboard.putString(null, "This should not work"));
}
@Test
void putStringNullValueTest() {
- assertThrows(NullPointerException.class,
+ assertThrows(
+ NullPointerException.class,
() -> SmartDashboard.putString("KEY_SHOULD_NOT_BE_STORED", null));
}
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java
deleted file mode 100644
index 231eab6..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ColorTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.util;
-
-import java.util.stream.Stream;
-
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.params.provider.Arguments.arguments;
-
-class ColorTest {
- private static final double kEpsilon = 1e-3;
-
- void assertColorMatches(double red, double green, double blue, Color color) {
- assertAll(
- () -> assertEquals(red, color.red, kEpsilon),
- () -> assertEquals(green, color.green, kEpsilon),
- () -> assertEquals(blue, color.blue, kEpsilon)
- );
- }
-
- @ParameterizedTest
- @MethodSource("staticColorProvider")
- void staticColorTest(double red, double green, double blue, Color color) {
- assertColorMatches(red, green, blue, color);
- }
-
- @ParameterizedTest
- @MethodSource("staticColorProvider")
- void colorEqualsTest(double red, double green, double blue, Color color) {
- assertEquals(color, new Color(red, green, blue));
- }
-
- static Stream<Arguments> staticColorProvider() {
- return Stream.of(
- arguments(0.0823529412, 0.376470589, 0.7411764706, Color.kDenim),
- arguments(0.0, 0.4, 0.7019607844, Color.kFirstBlue),
- arguments(0.9294117648, 0.1098039216, 0.1411764706, Color.kFirstRed)
- );
- }
-}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ErrorMessagesTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ErrorMessagesTest.java
deleted file mode 100644
index 839e2e3..0000000
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/util/ErrorMessagesTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.wpilibj.util;
-
-import org.junit.jupiter.api.Test;
-
-import edu.wpi.first.wpilibj.UtilityClassTest;
-
-import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class ErrorMessagesTest extends UtilityClassTest<ErrorMessages> {
- ErrorMessagesTest() {
- super(ErrorMessages.class);
- }
-
- @Test
- void requireNonNullParamNullTest() {
- assertThrows(NullPointerException.class, () -> requireNonNullParam(null, "testParam",
- "testMethod"));
- }
-
- @Test
- void requireNonNullParamNotNullTest() {
- assertDoesNotThrow(() -> requireNonNullParam("null", "testParam", "testMethod"));
- }
-}
diff --git a/wpilibj/src/test/resources/edu/wpi/first/wpilibj/PreferencesTestDefault.ini b/wpilibj/src/test/resources/edu/wpi/first/wpilibj/PreferencesTestDefault.ini
index a685de0..f271944 100644
--- a/wpilibj/src/test/resources/edu/wpi/first/wpilibj/PreferencesTestDefault.ini
+++ b/wpilibj/src/test/resources/edu/wpi/first/wpilibj/PreferencesTestDefault.ini
@@ -1,7 +1,8 @@
[NetworkTables Storage 3.0]
double "/Preferences/checkedValueInt"=2
+; The omission of a leading zero is intentional for testing purposes
double "/Preferences/checkedValueDouble"=.2
-double "/Preferences/checkedValueFloat"=3.14
+double "/Preferences/checkedValueFloat"=3.4
double "/Preferences/checkedValueLong"=172
string "/Preferences/checkedValueString"="Hello. How are you?"
boolean "/Preferences/checkedValueBoolean"=false