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/wpilibc/src/main/native/include/WPILibVersion.h b/wpilibc/src/main/native/include/WPILibVersion.h
index 8aab880..c11bef9 100644
--- a/wpilibc/src/main/native/include/WPILibVersion.h
+++ b/wpilibc/src/main/native/include/WPILibVersion.h
@@ -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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/ADXL345_I2C.h b/wpilibc/src/main/native/include/frc/ADXL345_I2C.h
index 202acbb..c997327 100644
--- a/wpilibc/src/main/native/include/frc/ADXL345_I2C.h
+++ b/wpilibc/src/main/native/include/frc/ADXL345_I2C.h
@@ -1,24 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <hal/SimDevice.h>
+#include <networktables/NTSendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
-#include "frc/ErrorBase.h"
 #include "frc/I2C.h"
 #include "frc/interfaces/Accelerometer.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * ADXL345 Accelerometer on I2C.
  *
@@ -26,10 +20,9 @@
  * an I2C bus. This class assumes the default (not alternate) sensor address of
  * 0x1D (7-bit address).
  */
-class ADXL345_I2C : public ErrorBase,
-                    public Accelerometer,
-                    public Sendable,
-                    public SendableHelper<ADXL345_I2C> {
+class ADXL345_I2C : public Accelerometer,
+                    public nt::NTSendable,
+                    public wpi::SendableHelper<ADXL345_I2C> {
  public:
   enum Axes { kAxis_X = 0x00, kAxis_Y = 0x02, kAxis_Z = 0x04 };
 
@@ -53,8 +46,11 @@
   ADXL345_I2C(ADXL345_I2C&&) = default;
   ADXL345_I2C& operator=(ADXL345_I2C&&) = default;
 
+  I2C::Port GetI2CPort() const;
+  int GetI2CDeviceAddress() const;
+
   // Accelerometer interface
-  void SetRange(Range range) override;
+  void SetRange(Range range) final;
   double GetX() override;
   double GetY() override;
   double GetZ() override;
@@ -75,7 +71,7 @@
    */
   virtual AllAxes GetAccelerations();
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(nt::NTSendableBuilder& builder) override;
 
  protected:
   I2C m_i2c;
diff --git a/wpilibc/src/main/native/include/frc/ADXL345_SPI.h b/wpilibc/src/main/native/include/frc/ADXL345_SPI.h
index 90454c0..18d48a3 100644
--- a/wpilibc/src/main/native/include/frc/ADXL345_SPI.h
+++ b/wpilibc/src/main/native/include/frc/ADXL345_SPI.h
@@ -1,19 +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.
 
 #pragma once
 
 #include <hal/SimDevice.h>
+#include <networktables/NTSendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
-#include "frc/ErrorBase.h"
 #include "frc/SPI.h"
 #include "frc/interfaces/Accelerometer.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
@@ -23,10 +19,9 @@
  * This class allows access to an Analog Devices ADXL345 3-axis accelerometer
  * via SPI. This class assumes the sensor is wired in 4-wire SPI mode.
  */
-class ADXL345_SPI : public ErrorBase,
-                    public Accelerometer,
-                    public Sendable,
-                    public SendableHelper<ADXL345_SPI> {
+class ADXL345_SPI : public Accelerometer,
+                    public nt::NTSendable,
+                    public wpi::SendableHelper<ADXL345_SPI> {
  public:
   enum Axes { kAxis_X = 0x00, kAxis_Y = 0x02, kAxis_Z = 0x04 };
 
@@ -49,8 +44,10 @@
   ADXL345_SPI(ADXL345_SPI&&) = default;
   ADXL345_SPI& operator=(ADXL345_SPI&&) = default;
 
+  SPI::Port GetSpiPort() const;
+
   // Accelerometer interface
-  void SetRange(Range range) override;
+  void SetRange(Range range) final;
   double GetX() override;
   double GetY() override;
   double GetZ() override;
@@ -71,7 +68,7 @@
    */
   virtual AllAxes GetAccelerations();
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(nt::NTSendableBuilder& builder) override;
 
  protected:
   SPI m_spi;
diff --git a/wpilibc/src/main/native/include/frc/ADXL362.h b/wpilibc/src/main/native/include/frc/ADXL362.h
index e1d659b..451b5fb 100644
--- a/wpilibc/src/main/native/include/frc/ADXL362.h
+++ b/wpilibc/src/main/native/include/frc/ADXL362.h
@@ -1,33 +1,26 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <hal/SimDevice.h>
+#include <networktables/NTSendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
-#include "frc/ErrorBase.h"
 #include "frc/SPI.h"
 #include "frc/interfaces/Accelerometer.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * ADXL362 SPI Accelerometer.
  *
  * This class allows access to an Analog Devices ADXL362 3-axis accelerometer.
  */
-class ADXL362 : public ErrorBase,
-                public Accelerometer,
-                public Sendable,
-                public SendableHelper<ADXL362> {
+class ADXL362 : public Accelerometer,
+                public nt::NTSendable,
+                public wpi::SendableHelper<ADXL362> {
  public:
   enum Axes { kAxis_X = 0x00, kAxis_Y = 0x02, kAxis_Z = 0x04 };
   struct AllAxes {
@@ -57,8 +50,10 @@
   ADXL362(ADXL362&&) = default;
   ADXL362& operator=(ADXL362&&) = default;
 
+  SPI::Port GetSpiPort() const;
+
   // Accelerometer interface
-  void SetRange(Range range) override;
+  void SetRange(Range range) final;
   double GetX() override;
   double GetY() override;
   double GetZ() override;
@@ -79,7 +74,7 @@
    */
   virtual AllAxes GetAccelerations();
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(nt::NTSendableBuilder& builder) override;
 
  private:
   SPI m_spi;
diff --git a/wpilibc/src/main/native/include/frc/ADXRS450_Gyro.h b/wpilibc/src/main/native/include/frc/ADXRS450_Gyro.h
index 309fab3..cb0dff8 100644
--- a/wpilibc/src/main/native/include/frc/ADXRS450_Gyro.h
+++ b/wpilibc/src/main/native/include/frc/ADXRS450_Gyro.h
@@ -1,25 +1,24 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <stdint.h>
 
 #include <hal/SimDevice.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
-#include "frc/GyroBase.h"
 #include "frc/SPI.h"
+#include "frc/interfaces/Gyro.h"
 
 namespace frc {
 
 /**
  * Use a rate gyro to return the robots heading relative to a starting position.
  *
- * The Gyro class tracks the robots heading based on the starting position. As
+ * The %Gyro class tracks the robots heading based on the starting position. As
  * the robot rotates the new heading is computed by integrating the rate of
  * rotation returned by the sensor. When the class is instantiated, it does a
  * short calibration routine where it samples the gyro while at rest to
@@ -27,17 +26,19 @@
  * determine the heading.
  *
  * This class is for the digital ADXRS450 gyro sensor that connects via SPI.
- * Only one instance of an ADXRS Gyro is supported.
+ * Only one instance of an ADXRS %Gyro is supported.
  */
-class ADXRS450_Gyro : public GyroBase {
+class ADXRS450_Gyro : public Gyro,
+                      public wpi::Sendable,
+                      public wpi::SendableHelper<ADXRS450_Gyro> {
  public:
   /**
-   * Gyro constructor on onboard CS0.
+   * %Gyro constructor on onboard CS0.
    */
   ADXRS450_Gyro();
 
   /**
-   * Gyro constructor on the specified SPI port.
+   * %Gyro constructor on the specified SPI port.
    *
    * @param port The SPI port the gyro is attached to.
    */
@@ -90,7 +91,7 @@
    * robot is first turned on while it's sitting at rest before the competition
    * starts.
    */
-  void Calibrate() override;
+  void Calibrate() final;
 
   /**
    * Get the SPI port number.
@@ -99,6 +100,8 @@
    */
   int GetPort() const;
 
+  void InitSendable(wpi::SendableBuilder& builder) override;
+
  private:
   SPI m_spi;
   SPI::Port m_port;
diff --git a/wpilibc/src/main/native/include/frc/AddressableLED.h b/wpilibc/src/main/native/include/frc/AddressableLED.h
index 3bcbab5..561eb37 100644
--- a/wpilibc/src/main/native/include/frc/AddressableLED.h
+++ b/wpilibc/src/main/native/include/frc/AddressableLED.h
@@ -1,20 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <memory>
+#include <initializer_list>
 
 #include <hal/AddressableLEDTypes.h>
 #include <hal/Types.h>
 #include <units/time.h>
-#include <wpi/ArrayRef.h>
+#include <wpi/span.h>
 
-#include "frc/ErrorBase.h"
 #include "util/Color.h"
 #include "util/Color8Bit.h"
 
@@ -25,7 +21,7 @@
  *
  * <p>Only 1 LED driver is currently supported by the roboRIO.
  */
-class AddressableLED : public ErrorBase {
+class AddressableLED {
  public:
   class LEDData : public HAL_AddressableLEDData {
    public:
@@ -89,7 +85,7 @@
    */
   explicit AddressableLED(int port);
 
-  ~AddressableLED() override;
+  ~AddressableLED();
 
   /**
    * Sets the length of the LED strip.
@@ -111,7 +107,7 @@
    *
    * @param ledData the buffer to write
    */
-  void SetData(wpi::ArrayRef<LEDData> ledData);
+  void SetData(wpi::span<const LEDData> ledData);
 
   /**
    * Sets the led output data.
@@ -144,7 +140,7 @@
    * <p>The sync time is the time to hold output so LEDs enable. Default set for
    * WS2812.
    *
-   * @param syncTimeMicroSeconds the sync time
+   * @param syncTime the sync time
    */
   void SetSyncTime(units::microsecond_t syncTime);
 
@@ -163,5 +159,6 @@
  private:
   hal::Handle<HAL_DigitalHandle> m_pwmHandle;
   hal::Handle<HAL_AddressableLEDHandle> m_handle;
+  int m_port;
 };
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/AnalogAccelerometer.h b/wpilibc/src/main/native/include/frc/AnalogAccelerometer.h
index 27015e4..b14ff7c 100644
--- a/wpilibc/src/main/native/include/frc/AnalogAccelerometer.h
+++ b/wpilibc/src/main/native/include/frc/AnalogAccelerometer.h
@@ -1,24 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
 
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
 #include "frc/AnalogInput.h"
-#include "frc/ErrorBase.h"
-#include "frc/PIDSource.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * Handle operation of an analog accelerometer.
  *
@@ -26,10 +20,8 @@
  * sensors have multiple axis and can be treated as multiple devices. Each is
  * calibrated by finding the center value over a period of time.
  */
-class AnalogAccelerometer : public ErrorBase,
-                            public PIDSource,
-                            public Sendable,
-                            public SendableHelper<AnalogAccelerometer> {
+class AnalogAccelerometer : public wpi::Sendable,
+                            public wpi::SendableHelper<AnalogAccelerometer> {
  public:
   /**
    * Create a new instance of an accelerometer.
@@ -100,14 +92,7 @@
    */
   void SetZero(double zero);
 
-  /**
-   * Get the Acceleration for the PID Source parent.
-   *
-   * @return The current acceleration in Gs.
-   */
-  double PIDGet() override;
-
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   /**
diff --git a/wpilibc/src/main/native/include/frc/AnalogEncoder.h b/wpilibc/src/main/native/include/frc/AnalogEncoder.h
index 3dc22ea..6f12cb8 100644
--- a/wpilibc/src/main/native/include/frc/AnalogEncoder.h
+++ b/wpilibc/src/main/native/include/frc/AnalogEncoder.h
@@ -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.
 
 #pragma once
 
@@ -12,12 +9,11 @@
 #include <hal/SimDevice.h>
 #include <hal/Types.h>
 #include <units/angle.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/AnalogTrigger.h"
 #include "frc/Counter.h"
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 class AnalogInput;
@@ -25,11 +21,17 @@
 /**
  * Class for supporting continuous analog encoders, such as the US Digital MA3.
  */
-class AnalogEncoder : public ErrorBase,
-                      public Sendable,
-                      public SendableHelper<AnalogEncoder> {
+class AnalogEncoder : public wpi::Sendable,
+                      public wpi::SendableHelper<AnalogEncoder> {
  public:
   /**
+   * Construct a new AnalogEncoder attached to a specific AnalogIn channel.
+   *
+   * @param channel the analog input channel to attach to
+   */
+  explicit AnalogEncoder(int channel);
+
+  /**
    * Construct a new AnalogEncoder attached to a specific AnalogInput.
    *
    * @param analogInput the analog input to attach to
@@ -115,7 +117,7 @@
    */
   int GetChannel() const;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   void Init();
diff --git a/wpilibc/src/main/native/include/frc/AnalogGyro.h b/wpilibc/src/main/native/include/frc/AnalogGyro.h
index b59df5b..6565c93 100644
--- a/wpilibc/src/main/native/include/frc/AnalogGyro.h
+++ b/wpilibc/src/main/native/include/frc/AnalogGyro.h
@@ -1,19 +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.
 
 #pragma once
 
 #include <memory>
 
 #include <hal/Types.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
-#include "frc/GyroBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include "frc/interfaces/Gyro.h"
 
 namespace frc {
 
@@ -32,7 +29,9 @@
  *
  * This class is for gyro sensors that connect to an analog input.
  */
-class AnalogGyro : public GyroBase {
+class AnalogGyro : public Gyro,
+                   public wpi::Sendable,
+                   public wpi::SendableHelper<AnalogGyro> {
  public:
   static constexpr int kOversampleBits = 10;
   static constexpr int kAverageBits = 0;
@@ -41,7 +40,7 @@
   static constexpr double kDefaultVoltsPerDegreePerSecond = 0.007;
 
   /**
-   * Gyro constructor using the Analog Input channel number.
+   * %Gyro constructor using the Analog Input channel number.
    *
    * @param channel The analog channel the gyro is connected to. Gyros can only
    *                be used on on-board Analog Inputs 0-1.
@@ -63,7 +62,7 @@
   explicit AnalogGyro(AnalogInput* channel);
 
   /**
-   * Gyro constructor with a precreated AnalogInput object.
+   * %Gyro constructor with a precreated AnalogInput object.
    *
    * Use this constructor when the analog channel needs to be shared.
    * This object will not clean up the AnalogInput object when using this
@@ -75,7 +74,7 @@
   explicit AnalogGyro(std::shared_ptr<AnalogInput> channel);
 
   /**
-   * Gyro constructor using the Analog Input channel number with parameters for
+   * %Gyro constructor using the Analog Input channel number with parameters for
    * presetting the center and offset values. Bypasses calibration.
    *
    * @param channel The analog channel the gyro is connected to. Gyros can only
@@ -87,7 +86,7 @@
   AnalogGyro(int channel, int center, double offset);
 
   /**
-   * Gyro constructor with a precreated AnalogInput object and calibrated
+   * %Gyro constructor with a precreated AnalogInput object and calibrated
    * parameters.
    *
    * Use this constructor when the analog channel needs to be shared.
@@ -104,8 +103,8 @@
 
   ~AnalogGyro() override;
 
-  AnalogGyro(AnalogGyro&& rhs);
-  AnalogGyro& operator=(AnalogGyro&& rhs);
+  AnalogGyro(AnalogGyro&& rhs) = default;
+  AnalogGyro& operator=(AnalogGyro&& rhs) = default;
 
   /**
    * Return the actual angle in degrees that the robot is currently facing.
@@ -175,16 +174,16 @@
    * significant drift in the gyro and it needs to be recalibrated after it has
    * been running.
    */
-  void Reset() override;
+  void Reset() final;
 
   /**
    * Initialize the gyro.
    *
    * Calibration is handled by Calibrate().
    */
-  virtual void InitGyro();
+  void InitGyro();
 
-  void Calibrate() override;
+  void Calibrate() final;
 
   /**
    * Gets the analog input for the gyro.
@@ -193,6 +192,8 @@
    */
   std::shared_ptr<AnalogInput> GetAnalogInput() const;
 
+  void InitSendable(wpi::SendableBuilder& builder) override;
+
  protected:
   std::shared_ptr<AnalogInput> m_analog;
 
diff --git a/wpilibc/src/main/native/include/frc/AnalogInput.h b/wpilibc/src/main/native/include/frc/AnalogInput.h
index 3d14c4c..ebc4e70 100644
--- a/wpilibc/src/main/native/include/frc/AnalogInput.h
+++ b/wpilibc/src/main/native/include/frc/AnalogInput.h
@@ -1,24 +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.
 
 #pragma once
 
 #include <stdint.h>
 
 #include <hal/Types.h>
-
-#include "frc/ErrorBase.h"
-#include "frc/PIDSource.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 namespace frc {
 
-class SendableBuilder;
 class DMA;
 class DMASample;
 
@@ -34,10 +27,8 @@
  * are divided by the number of samples to retain the resolution, but get more
  * stable values.
  */
-class AnalogInput : public ErrorBase,
-                    public PIDSource,
-                    public Sendable,
-                    public SendableHelper<AnalogInput> {
+class AnalogInput : public wpi::Sendable,
+                    public wpi::SendableHelper<AnalogInput> {
   friend class AnalogTrigger;
   friend class AnalogGyro;
   friend class DMA;
@@ -207,8 +198,7 @@
    *
    * This will be added to all values returned to the user.
    *
-   * @param initialValue The value that the accumulator should start from when
-   *                     reset.
+   * @param value The value that the accumulator should start from when reset.
    */
   void SetAccumulatorInitialValue(int64_t value);
 
@@ -284,20 +274,13 @@
   static double GetSampleRate();
 
   /**
-   * Get the Average value for the PID Source base object.
-   *
-   * @return The average voltage.
-   */
-  double PIDGet() override;
-
-  /**
    * Indicates this input is used by a simulated device.
    *
    * @param device simulated device handle
    */
   void SetSimDevice(HAL_SimDeviceHandle device);
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   int m_channel;
diff --git a/wpilibc/src/main/native/include/frc/AnalogOutput.h b/wpilibc/src/main/native/include/frc/AnalogOutput.h
index 026986b..ccb3c9c 100644
--- a/wpilibc/src/main/native/include/frc/AnalogOutput.h
+++ b/wpilibc/src/main/native/include/frc/AnalogOutput.h
@@ -1,28 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <hal/Types.h>
-
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * MXP analog output class.
  */
-class AnalogOutput : public ErrorBase,
-                     public Sendable,
-                     public SendableHelper<AnalogOutput> {
+class AnalogOutput : public wpi::Sendable,
+                     public wpi::SendableHelper<AnalogOutput> {
  public:
   /**
    * Construct an analog output on the given channel.
@@ -57,7 +49,7 @@
    */
   int GetChannel() const;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  protected:
   int m_channel;
diff --git a/wpilibc/src/main/native/include/frc/AnalogPotentiometer.h b/wpilibc/src/main/native/include/frc/AnalogPotentiometer.h
index ed943f7..3d0588d 100644
--- a/wpilibc/src/main/native/include/frc/AnalogPotentiometer.h
+++ b/wpilibc/src/main/native/include/frc/AnalogPotentiometer.h
@@ -1,34 +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.
 
 #pragma once
 
 #include <memory>
 
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
 #include "frc/AnalogInput.h"
-#include "frc/ErrorBase.h"
-#include "frc/interfaces/Potentiometer.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * 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.
  */
-class AnalogPotentiometer : public ErrorBase,
-                            public Potentiometer,
-                            public Sendable,
-                            public SendableHelper<AnalogPotentiometer> {
+class AnalogPotentiometer : public wpi::Sendable,
+                            public wpi::SendableHelper<AnalogPotentiometer> {
  public:
   /**
    * Construct an Analog Potentiometer object from a channel number.
@@ -66,7 +58,7 @@
    * This will calculate the result from the fullRange times the fraction of the
    * supply voltage, plus the offset.
    *
-   * @param channel   The existing Analog Input pointer
+   * @param input     The existing Analog Input pointer
    * @param fullRange The value (in desired units) representing the full
    *                  0-5V range of the input.
    * @param offset    The value (in desired units) representing the
@@ -88,7 +80,7 @@
    * This will calculate the result from the fullRange times the fraction of the
    * supply voltage, plus the offset.
    *
-   * @param channel   The existing Analog Input pointer
+   * @param input     The existing Analog Input pointer
    * @param fullRange The value (in desired units) representing the full
    *                  0-5V range of the input.
    * @param offset    The value (in desired units) representing the
@@ -108,16 +100,9 @@
    * @return The current position of the potentiometer (in the units used for
    *         fullRange and offset).
    */
-  double Get() const override;
+  double Get() const;
 
-  /**
-   * Implement the PIDSource interface.
-   *
-   * @return The current reading.
-   */
-  double PIDGet() override;
-
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   std::shared_ptr<AnalogInput> m_analog_input;
diff --git a/wpilibc/src/main/native/include/frc/AnalogTrigger.h b/wpilibc/src/main/native/include/frc/AnalogTrigger.h
index d465652..f9c5602 100644
--- a/wpilibc/src/main/native/include/frc/AnalogTrigger.h
+++ b/wpilibc/src/main/native/include/frc/AnalogTrigger.h
@@ -1,30 +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.
 
 #pragma once
 
 #include <memory>
 
 #include <hal/Types.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/AnalogTriggerOutput.h"
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
 class AnalogInput;
 class DutyCycle;
-class SendableBuilder;
 
-class AnalogTrigger : public ErrorBase,
-                      public Sendable,
-                      public SendableHelper<AnalogTrigger> {
+class AnalogTrigger : public wpi::Sendable,
+                      public wpi::SendableHelper<AnalogTrigger> {
   friend class AnalogTriggerOutput;
 
  public:
@@ -42,21 +36,21 @@
    * This should be used in the case of sharing an analog channel between the
    * trigger and an analog input object.
    *
-   * @param channel The pointer to the existing AnalogInput object
+   * @param input The pointer to the existing AnalogInput object
    */
-  explicit AnalogTrigger(AnalogInput* channel);
+  explicit AnalogTrigger(AnalogInput* input);
 
   /**
    * Construct an analog trigger given a duty cycle input.
    *
-   * @param channel The pointer to the existing DutyCycle object
+   * @param dutyCycle The pointer to the existing DutyCycle object
    */
   explicit AnalogTrigger(DutyCycle* dutyCycle);
 
   ~AnalogTrigger() override;
 
-  AnalogTrigger(AnalogTrigger&& rhs);
-  AnalogTrigger& operator=(AnalogTrigger&& rhs);
+  AnalogTrigger(AnalogTrigger&&) = default;
+  AnalogTrigger& operator=(AnalogTrigger&&) = default;
 
   /**
    * Set the upper and lower limits of the analog trigger.
@@ -154,9 +148,11 @@
   std::shared_ptr<AnalogTriggerOutput> CreateOutput(
       AnalogTriggerType type) const;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
+  int GetSourceChannel() const;
+
   hal::Handle<HAL_AnalogTriggerHandle> m_trigger;
   AnalogInput* m_analogInput = nullptr;
   DutyCycle* m_dutyCycle = nullptr;
diff --git a/wpilibc/src/main/native/include/frc/AnalogTriggerOutput.h b/wpilibc/src/main/native/include/frc/AnalogTriggerOutput.h
index 989a93f..6f52cab 100644
--- a/wpilibc/src/main/native/include/frc/AnalogTriggerOutput.h
+++ b/wpilibc/src/main/native/include/frc/AnalogTriggerOutput.h
@@ -1,15 +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.
 
 #pragma once
 
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
 #include "frc/DigitalSource.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
@@ -47,8 +45,8 @@
  * may help with this, but rotational speeds of the sensor will then be limited.
  */
 class AnalogTriggerOutput : public DigitalSource,
-                            public Sendable,
-                            public SendableHelper<AnalogTriggerOutput> {
+                            public wpi::Sendable,
+                            public wpi::SendableHelper<AnalogTriggerOutput> {
   friend class AnalogTrigger;
 
  public:
@@ -80,7 +78,7 @@
    */
   int GetChannel() const override;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  protected:
   /**
diff --git a/wpilibc/src/main/native/include/frc/AnalogTriggerType.h b/wpilibc/src/main/native/include/frc/AnalogTriggerType.h
index f15fb03..c706c34 100644
--- a/wpilibc/src/main/native/include/frc/AnalogTriggerType.h
+++ b/wpilibc/src/main/native/include/frc/AnalogTriggerType.h
@@ -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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/AsynchronousInterrupt.h b/wpilibc/src/main/native/include/frc/AsynchronousInterrupt.h
new file mode 100644
index 0000000..4531dfd
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/AsynchronousInterrupt.h
@@ -0,0 +1,177 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <frc/SynchronousInterrupt.h>
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <thread>
+#include <utility>
+
+#include <units/time.h>
+
+namespace frc {
+/**
+ * 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.
+ */
+class AsynchronousInterrupt {
+ public:
+  /**
+   * Construct an Asynchronous Interrupt from a Digital Source.
+   *
+   * <p> At construction, the interrupt will trigger on the rising edge.
+   *
+   * <p> The first bool in the callback indicates the rising edge triggered the
+   * interrupt, the second bool is falling edge.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   * @param callback the callback function to call when the interrupt is
+   * triggered
+   */
+  AsynchronousInterrupt(DigitalSource& source,
+                        std::function<void(bool, bool)> callback);
+
+  /**
+   * Construct an Asynchronous Interrupt from a Digital Source.
+   *
+   * <p> At construction, the interrupt will trigger on the rising edge.
+   *
+   * <p> The first bool in the callback indicates the rising edge triggered the
+   * interrupt, the second bool is falling edge.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   * @param callback the callback function to call when the interrupt is
+   * triggered
+   */
+  AsynchronousInterrupt(DigitalSource* source,
+                        std::function<void(bool, bool)> callback);
+
+  /**
+   * Construct an Asynchronous Interrupt from a Digital Source.
+   *
+   * <p> At construction, the interrupt will trigger on the rising edge.
+   *
+   * <p> The first bool in the callback indicates the rising edge triggered the
+   * interrupt, the second bool is falling edge.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   * @param callback the callback function to call when the interrupt is
+   * triggered
+   */
+  AsynchronousInterrupt(std::shared_ptr<DigitalSource> source,
+                        std::function<void(bool, bool)> callback);
+
+  /**
+   * Construct an Asynchronous Interrupt from a Digital Source.
+   *
+   * <p> At construction, the interrupt will trigger on the rising edge.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   * @param f the callback function to call when the interrupt is triggered
+   * @param arg the first argument, interrupt was triggered on rising edge
+   * @param args the remaing arguments, interrupt was triggered on falling edge
+   */
+  template <typename Callable, typename Arg, typename... Args>
+  AsynchronousInterrupt(DigitalSource& source, Callable&& f, Arg&& arg,
+                        Args&&... args)
+      : AsynchronousInterrupt(
+            source, std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
+                              std::forward<Args>(args)...)) {}
+
+  /**
+   * Construct an Asynchronous Interrupt from a Digital Source.
+   *
+   * <p> At construction, the interrupt will trigger on the rising edge.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   * @param f the callback function to call when the interrupt is triggered
+   * @param arg the first argument, interrupt was triggered on rising edge
+   * @param args the remaing arguments, interrupt was triggered on falling edge
+   */
+  template <typename Callable, typename Arg, typename... Args>
+  AsynchronousInterrupt(DigitalSource* source, Callable&& f, Arg&& arg,
+                        Args&&... args)
+      : AsynchronousInterrupt(
+            source, std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
+                              std::forward<Args>(args)...)) {}
+
+  /**
+   * Construct an Asynchronous Interrupt from a Digital Source.
+   *
+   * <p> At construction, the interrupt will trigger on the rising edge.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   * @param f the callback function to call when the interrupt is triggered
+   * @param arg the first argument, interrupt was triggered on rising edge
+   * @param args the remaing arguments, interrupt was triggered on falling edge
+   */
+  template <typename Callable, typename Arg, typename... Args>
+  AsynchronousInterrupt(std::shared_ptr<DigitalSource> source, Callable&& f,
+                        Arg&& arg, Args&&... args)
+      : AsynchronousInterrupt(
+            source, std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
+                              std::forward<Args>(args)...)) {}
+
+  ~AsynchronousInterrupt();
+
+  /**
+   * Enables interrupt callbacks. Before this, callbacks will not occur. Does
+   * nothing if already enabled.
+   */
+  void Enable();
+
+  /**
+   * Disables interrupt callbacks. Does nothing if already disabled.
+   */
+  void Disable();
+
+  /**
+   * Set which edges to trigger the interrupt on.
+   *
+   * @param risingEdge %Trigger on rising edge
+   * @param fallingEdge %Trigger on falling edge
+   */
+  void SetInterruptEdges(bool risingEdge, bool 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
+   */
+  units::second_t 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
+   */
+  units::second_t GetFallingTimestamp();
+
+ private:
+  void ThreadMain();
+
+  std::atomic_bool m_keepRunning{false};
+  std::thread m_thread;
+  SynchronousInterrupt m_interrupt;
+  std::function<void(bool, bool)> m_callback;
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Base.h b/wpilibc/src/main/native/include/frc/Base.h
deleted file mode 100644
index 1fdbe5d..0000000
--- a/wpilibc/src/main/native/include/frc/Base.h
+++ /dev/null
@@ -1,35 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5
-static_assert(0,
-              "GCC must be 5 or greater. If building for the roboRIO, please "
-              "update to the 2018 toolchains.");
-#endif
-
-#if defined(_MSC_VER) && _MSC_VER < 1900
-static_assert(0, "Visual Studio 2015 or greater required.");
-#endif
-
-/** WPILib FRC namespace */
-namespace frc {
-
-// A struct to use as a deleter when a std::shared_ptr must wrap a raw pointer
-// that is being deleted by someone else.
-template <class T>
-struct NullDeleter {
-  void operator()(T*) const noexcept {};
-};
-
-}  // namespace frc
-
-// For backwards compatibility
-#ifdef NO_NAMESPACED_WPILIB
-using namespace frc;  // NOLINT
-#endif
diff --git a/wpilibc/src/main/native/include/frc/BuiltInAccelerometer.h b/wpilibc/src/main/native/include/frc/BuiltInAccelerometer.h
index 8148e72..0e5bee6 100644
--- a/wpilibc/src/main/native/include/frc/BuiltInAccelerometer.h
+++ b/wpilibc/src/main/native/include/frc/BuiltInAccelerometer.h
@@ -1,30 +1,24 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2014-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.
 
 #pragma once
 
-#include "frc/ErrorBase.h"
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
 #include "frc/interfaces/Accelerometer.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * Built-in accelerometer.
  *
  * This class allows access to the roboRIO's internal accelerometer.
  */
-class BuiltInAccelerometer : public ErrorBase,
-                             public Accelerometer,
-                             public Sendable,
-                             public SendableHelper<BuiltInAccelerometer> {
+class BuiltInAccelerometer : public Accelerometer,
+                             public wpi::Sendable,
+                             public wpi::SendableHelper<BuiltInAccelerometer> {
  public:
   /**
    * Constructor.
@@ -44,7 +38,7 @@
    *              accelerometer will measure. Not all accelerometers support all
    *              ranges.
    */
-  void SetRange(Range range) override;
+  void SetRange(Range range) final;
 
   /**
    * @return The acceleration of the roboRIO along the X axis in g-forces
@@ -61,7 +55,7 @@
    */
   double GetZ() override;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/CAN.h b/wpilibc/src/main/native/include/frc/CAN.h
index 612d533..4c9b9bd 100644
--- a/wpilibc/src/main/native/include/frc/CAN.h
+++ b/wpilibc/src/main/native/include/frc/CAN.h
@@ -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.
 
 #pragma once
 
@@ -11,8 +8,6 @@
 
 #include <hal/CANAPITypes.h>
 
-#include "frc/ErrorBase.h"
-
 namespace frc {
 struct CANData {
   uint8_t data[8];
@@ -30,7 +25,7 @@
  * All methods are thread save, however the buffer objects passed in
  * by the user need to not be modified for the duration of their calls.
  */
-class CAN : public ErrorBase {
+class CAN {
  public:
   /**
    * Create a new CAN communication interface with the specific device ID.
@@ -55,7 +50,7 @@
   /**
    * Closes the CAN communication.
    */
-  ~CAN() override;
+  ~CAN();
 
   CAN(CAN&&) = default;
   CAN& operator=(CAN&&) = default;
diff --git a/wpilibc/src/main/native/include/frc/Compressor.h b/wpilibc/src/main/native/include/frc/Compressor.h
index d1a4dca..cc065ff 100644
--- a/wpilibc/src/main/native/include/frc/Compressor.h
+++ b/wpilibc/src/main/native/include/frc/Compressor.h
@@ -1,28 +1,25 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <hal/Types.h>
+#include <memory>
 
-#include "frc/ErrorBase.h"
+#include <hal/Types.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
+#include "frc/PneumaticsBase.h"
+#include "frc/PneumaticsModuleType.h"
 #include "frc/SensorUtil.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
- * Class for operating a compressor connected to a %PCM (Pneumatic Control
- * Module).
+ * Class for operating a compressor connected to a pneumatics module.
  *
- * The PCM will automatically run in closed loop mode by default whenever a
+ * The module will automatically run in closed loop mode by default whenever a
  * 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
@@ -33,18 +30,28 @@
  * loop control. You can only turn off closed loop control, thereby stopping
  * the compressor from operating.
  */
-class Compressor : public ErrorBase,
-                   public Sendable,
-                   public SendableHelper<Compressor> {
+class Compressor : public wpi::Sendable,
+                   public wpi::SendableHelper<Compressor> {
  public:
   /**
-   * Constructor. The default PCM ID is 0.
+   * Constructs a compressor for a specified module and type.
    *
-   * @param module The PCM ID to use (0-62)
+   * @param module The module ID to use.
+   * @param moduleType The module type to use.
    */
-  explicit Compressor(int pcmID = SensorUtil::GetDefaultSolenoidModule());
+  Compressor(int module, PneumaticsModuleType moduleType);
 
-  ~Compressor() override = default;
+  /**
+   * Constructs a compressor for a default module and specified type.
+   *
+   * @param moduleType The module type to use.
+   */
+  explicit Compressor(PneumaticsModuleType moduleType);
+
+  ~Compressor() override;
+
+  Compressor(const Compressor&) = delete;
+  Compressor& operator=(const Compressor&) = delete;
 
   Compressor(Compressor&&) = default;
   Compressor& operator=(Compressor&&) = default;
@@ -100,92 +107,10 @@
    */
   bool GetClosedLoopControl() const;
 
-  /**
-   * Query if the compressor output has been disabled due to high current draw.
-   *
-   * @return true if PCM is in fault state : Compressor Drive is
-   *         disabled due to compressor current being too high.
-   */
-  bool GetCompressorCurrentTooHighFault() const;
-
-  /**
-   * Query if the compressor output has been disabled due to high current draw
-   * (sticky).
-   *
-   * A sticky fault will not clear on device reboot, it must be cleared through
-   * code or the webdash.
-   *
-   * @return true if PCM sticky fault is set : Compressor Drive is
-   *         disabled due to compressor current being too high.
-   */
-  bool GetCompressorCurrentTooHighStickyFault() const;
-
-  /**
-   * Query if the compressor output has been disabled due to a short circuit
-   * (sticky).
-   *
-   * A sticky fault will not clear on device reboot, it must be cleared through
-   * code or the webdash.
-   *
-   * @return true if PCM sticky fault is set : Compressor output
-   *         appears to be shorted.
-   */
-  bool GetCompressorShortedStickyFault() const;
-
-  /**
-   * Query if the compressor output has been disabled due to a short circuit.
-   *
-   * @return true if PCM is in fault state : Compressor output
-   *         appears to be shorted.
-   */
-  bool GetCompressorShortedFault() const;
-
-  /**
-   * Query if the compressor output does not appear to be wired (sticky).
-   *
-   * A sticky fault will not clear on device reboot, it must be cleared through
-   * code or the webdash.
-   *
-   * @return true if PCM sticky fault is set : Compressor does not
-   *         appear to be wired, i.e. compressor is not drawing enough current.
-   */
-  bool GetCompressorNotConnectedStickyFault() const;
-
-  /**
-   * Query if the compressor output does not appear to be wired.
-   *
-   * @return true if PCM is in fault state : Compressor does not
-   *         appear to be wired, i.e. compressor is not drawing enough current.
-   */
-  bool GetCompressorNotConnectedFault() const;
-
-  /**
-   * Clear ALL sticky faults inside PCM that Compressor is wired to.
-   *
-   * 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.
-   *
-   * If no sticky faults are set then this call will have no effect.
-   */
-  void ClearAllPCMStickyFaults();
-
-  /**
-   * Gets module number (CAN ID).
-   *
-   * @return Module number
-   */
-  int GetModule() const;
-
-  void InitSendable(SendableBuilder& builder) override;
-
- protected:
-  hal::Handle<HAL_CompressorHandle> m_compressorHandle;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
-  void SetCompressor(bool on);
-  int m_module;
+  std::shared_ptr<PneumaticsBase> m_module;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Controller.h b/wpilibc/src/main/native/include/frc/Controller.h
index c6b25ab..d750a0e 100644
--- a/wpilibc/src/main/native/include/frc/Controller.h
+++ b/wpilibc/src/main/native/include/frc/Controller.h
@@ -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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/Counter.h b/wpilibc/src/main/native/include/frc/Counter.h
index 2770a02..d501b7e 100644
--- a/wpilibc/src/main/native/include/frc/Counter.h
+++ b/wpilibc/src/main/native/include/frc/Counter.h
@@ -1,26 +1,22 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
 
 #include <hal/Types.h>
+#include <units/time.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/AnalogTrigger.h"
 #include "frc/CounterBase.h"
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
 class DigitalGlitchFilter;
-class SendableBuilder;
 class DMA;
 class DMASample;
 
@@ -34,10 +30,9 @@
  * All counters will immediately start counting - Reset() them if you need them
  * to be zeroed before use.
  */
-class Counter : public ErrorBase,
-                public CounterBase,
-                public Sendable,
-                public SendableHelper<Counter> {
+class Counter : public CounterBase,
+                public wpi::Sendable,
+                public wpi::SendableHelper<Counter> {
   friend class DMA;
   friend class DMASample;
 
@@ -82,7 +77,7 @@
    *
    * This is used if an existing digital input is to be shared by multiple other
    * objects such as encoders or if the Digital Source is not a Digital Input
-   * channel (such as an Analog Trigger).
+   * channel (such as an Analog %Trigger).
    *
    * The counter will start counting immediately.
    * @param source A pointer to the existing DigitalSource object. It will be
@@ -96,7 +91,7 @@
    *
    * This is used if an existing digital input is to be shared by multiple other
    * objects such as encoders or if the Digital Source is not a Digital Input
-   * channel (such as an Analog Trigger).
+   * channel (such as an Analog %Trigger).
    *
    * The counter will start counting immediately.
    *
@@ -373,7 +368,7 @@
    *
    * @returns The period between the last two pulses in units of seconds.
    */
-  double GetPeriod() const override;
+  units::second_t GetPeriod() const override;
 
   /**
    * Set the maximum period where the device is still considered "moving".
@@ -385,7 +380,7 @@
    * @param maxPeriod The maximum period where the counted device is considered
    *                  moving in seconds.
    */
-  void SetMaxPeriod(double maxPeriod) override;
+  void SetMaxPeriod(units::second_t maxPeriod) final;
 
   /**
    * Select whether you want to continue updating the event timer output when
@@ -425,7 +420,7 @@
    */
   bool GetDirection() const override;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  protected:
   // Makes the counter count up.
diff --git a/wpilibc/src/main/native/include/frc/CounterBase.h b/wpilibc/src/main/native/include/frc/CounterBase.h
index 7fde3ac..33febbf 100644
--- a/wpilibc/src/main/native/include/frc/CounterBase.h
+++ b/wpilibc/src/main/native/include/frc/CounterBase.h
@@ -1,12 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
+#include <units/time.h>
+
 namespace frc {
 
 /**
@@ -30,8 +29,8 @@
 
   virtual int Get() const = 0;
   virtual void Reset() = 0;
-  virtual double GetPeriod() const = 0;
-  virtual void SetMaxPeriod(double maxPeriod) = 0;
+  virtual units::second_t GetPeriod() const = 0;
+  virtual void SetMaxPeriod(units::second_t maxPeriod) = 0;
   virtual bool GetStopped() const = 0;
   virtual bool GetDirection() const = 0;
 };
diff --git a/wpilibc/src/main/native/include/frc/DMA.h b/wpilibc/src/main/native/include/frc/DMA.h
index 57cdd27..1bbf268 100644
--- a/wpilibc/src/main/native/include/frc/DMA.h
+++ b/wpilibc/src/main/native/include/frc/DMA.h
@@ -1,15 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <hal/Types.h>
-
-#include "frc/ErrorBase.h"
+#include <units/time.h>
 
 namespace frc {
 class Encoder;
@@ -18,19 +14,22 @@
 class DutyCycle;
 class AnalogInput;
 class DMASample;
+class PWM;
+class PWMMotorController;
 
-class DMA : public ErrorBase {
+class DMA {
   friend class DMASample;
 
  public:
   DMA();
-  ~DMA() override;
+  ~DMA();
 
   DMA& operator=(DMA&& other) = default;
   DMA(DMA&& other) = default;
 
   void SetPause(bool pause);
-  void SetRate(int cycles);
+  void SetTimedTrigger(units::second_t seconds);
+  void SetTimedTriggerCycles(int cycles);
 
   void AddEncoder(const Encoder* encoder);
   void AddEncoderPeriod(const Encoder* encoder);
@@ -46,10 +45,15 @@
   void AddAveragedAnalogInput(const AnalogInput* analogInput);
   void AddAnalogAccumulator(const AnalogInput* analogInput);
 
-  void SetExternalTrigger(DigitalSource* source, bool rising, bool falling);
+  int SetExternalTrigger(DigitalSource* source, bool rising, bool falling);
+  int SetPwmEdgeTrigger(PWM* pwm, bool rising, bool falling);
+  int SetPwmEdgeTrigger(PWMMotorController* pwm, bool rising, bool falling);
 
-  void StartDMA(int queueDepth);
-  void StopDMA();
+  void ClearSensors();
+  void ClearExternalTriggers();
+
+  void Start(int queueDepth);
+  void Stop();
 
  private:
   hal::Handle<HAL_DMAHandle> dmaHandle;
diff --git a/wpilibc/src/main/native/include/frc/DMASample.h b/wpilibc/src/main/native/include/frc/DMASample.h
index c286c8d..48a0a9e 100644
--- a/wpilibc/src/main/native/include/frc/DMASample.h
+++ b/wpilibc/src/main/native/include/frc/DMASample.h
@@ -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.
 
 #pragma once
 
@@ -22,11 +19,16 @@
 namespace frc {
 class DMASample : public HAL_DMASample {
  public:
-  HAL_DMAReadStatus Update(const DMA* dma, units::second_t timeout,
-                           int32_t* remaining, int32_t* status) {
-    units::millisecond_t ms = timeout;
-    auto timeoutMs = ms.to<int32_t>();
-    return HAL_ReadDMA(dma->dmaHandle, this, timeoutMs, remaining, status);
+  enum class DMAReadStatus {
+    kOk = HAL_DMA_OK,
+    kTimeout = HAL_DMA_TIMEOUT,
+    kError = HAL_DMA_ERROR
+  };
+
+  DMAReadStatus Update(const DMA* dma, units::second_t timeout,
+                       int32_t* remaining, int32_t* status) {
+    return static_cast<DMAReadStatus>(
+        HAL_ReadDMA(dma->dmaHandle, this, timeout.value(), remaining, status));
   }
 
   uint64_t GetTime() const { return timeStamp; }
diff --git a/wpilibc/src/main/native/include/frc/DSControlWord.h b/wpilibc/src/main/native/include/frc/DSControlWord.h
new file mode 100644
index 0000000..fb0709f
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/DSControlWord.h
@@ -0,0 +1,102 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <hal/DriverStationTypes.h>
+
+namespace frc {
+
+/**
+ * A wrapper around Driver Station control word.
+ */
+class DSControlWord {
+ public:
+  /**
+   * DSControlWord constructor.
+   *
+   * Upon construction, the current Driver Station control word is read and
+   * stored internally.
+   */
+  DSControlWord();
+
+  /**
+   * Check if the DS has enabled the robot.
+   *
+   * @return True if the robot is enabled and the DS is connected
+   */
+  bool IsEnabled() const;
+
+  /**
+   * Check if the robot is disabled.
+   *
+   * @return True if the robot is explicitly disabled or the DS is not connected
+   */
+  bool IsDisabled() const;
+
+  /**
+   * Check if the robot is e-stopped.
+   *
+   * @return True if the robot is e-stopped
+   */
+  bool IsEStopped() const;
+
+  /**
+   * Check if the DS is commanding autonomous mode.
+   *
+   * @return True if the robot is being commanded to be in autonomous mode
+   */
+  bool IsAutonomous() const;
+
+  /**
+   * Check if the DS is commanding autonomous mode and if it has enabled the
+   * robot.
+   *
+   * @return True if the robot is being commanded to be in autonomous mode and
+   * enabled.
+   */
+  bool IsAutonomousEnabled() const;
+
+  /**
+   * Check if the DS is commanding teleop mode.
+   *
+   * @return True if the robot is being commanded to be in teleop mode
+   */
+  bool IsTeleop() const;
+
+  /**
+   * Check if the DS is commanding teleop mode and if it has enabled the robot.
+   *
+   * @return True if the robot is being commanded to be in teleop mode and
+   * enabled.
+   */
+  bool IsTeleopEnabled() const;
+
+  /**
+   * Check if the DS is commanding test mode.
+   *
+   * @return True if the robot is being commanded to be in test mode
+   */
+  bool IsTest() const;
+
+  /**
+   * Check if the DS is attached.
+   *
+   * @return True if the DS is connected to the robot
+   */
+  bool IsDSAttached() const;
+
+  /**
+   * Is 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
+   */
+  bool IsFMSAttached() const;
+
+ private:
+  HAL_ControlWord m_controlWord;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Debouncer.h b/wpilibc/src/main/native/include/frc/Debouncer.h
new file mode 100644
index 0000000..8f583f0
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/Debouncer.h
@@ -0,0 +1,46 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <units/time.h>
+
+#include "frc/Timer.h"
+
+namespace frc {
+/**
+ * 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.
+ */
+class Debouncer {
+ public:
+  enum DebounceType { kRising, kFalling, kBoth };
+
+  /**
+   * 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.
+   */
+  explicit Debouncer(units::second_t debounceTime,
+                     DebounceType type = 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.
+   */
+  bool Calculate(bool input);
+
+ private:
+  frc::Timer m_timer;
+  units::second_t m_debounceTime;
+  bool m_baseline;
+  DebounceType m_debounceType;
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/DigitalGlitchFilter.h b/wpilibc/src/main/native/include/frc/DigitalGlitchFilter.h
index 0690e53..7172f21 100644
--- a/wpilibc/src/main/native/include/frc/DigitalGlitchFilter.h
+++ b/wpilibc/src/main/native/include/frc/DigitalGlitchFilter.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -12,11 +9,10 @@
 #include <array>
 
 #include <wpi/mutex.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/DigitalSource.h"
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
@@ -30,15 +26,14 @@
  * filter. The filter lets the user configure the time that an input must remain
  * high or low before it is classified as high or low.
  */
-class DigitalGlitchFilter : public ErrorBase,
-                            public Sendable,
-                            public SendableHelper<DigitalGlitchFilter> {
+class DigitalGlitchFilter : public wpi::Sendable,
+                            public wpi::SendableHelper<DigitalGlitchFilter> {
  public:
   DigitalGlitchFilter();
   ~DigitalGlitchFilter() override;
 
-  DigitalGlitchFilter(DigitalGlitchFilter&& rhs);
-  DigitalGlitchFilter& operator=(DigitalGlitchFilter&& rhs);
+  DigitalGlitchFilter(DigitalGlitchFilter&&) = default;
+  DigitalGlitchFilter& operator=(DigitalGlitchFilter&&) = default;
 
   /**
    * Assigns the DigitalSource to this glitch filter.
@@ -119,7 +114,7 @@
    */
   uint64_t GetPeriodNanoSeconds();
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   // Sets the filter for the input to be the requested index. A value of 0
diff --git a/wpilibc/src/main/native/include/frc/DigitalInput.h b/wpilibc/src/main/native/include/frc/DigitalInput.h
index 33aa716..cee31fd 100644
--- a/wpilibc/src/main/native/include/frc/DigitalInput.h
+++ b/wpilibc/src/main/native/include/frc/DigitalInput.h
@@ -1,20 +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.
 
 #pragma once
 
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
 #include "frc/DigitalSource.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
 class DigitalGlitchFilter;
-class SendableBuilder;
 
 /**
  * Class to read a digital input.
@@ -26,8 +23,8 @@
  * implemented anywhere else.
  */
 class DigitalInput : public DigitalSource,
-                     public Sendable,
-                     public SendableHelper<DigitalInput> {
+                     public wpi::Sendable,
+                     public wpi::SendableHelper<DigitalInput> {
  public:
   /**
    * Create an instance of a Digital Input class.
@@ -78,7 +75,7 @@
    */
   void SetSimDevice(HAL_SimDeviceHandle device);
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   int m_channel;
diff --git a/wpilibc/src/main/native/include/frc/DigitalOutput.h b/wpilibc/src/main/native/include/frc/DigitalOutput.h
index 1d1d152..0e124f1 100644
--- a/wpilibc/src/main/native/include/frc/DigitalOutput.h
+++ b/wpilibc/src/main/native/include/frc/DigitalOutput.h
@@ -1,22 +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.
 
 #pragma once
 
 #include <hal/Types.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/DigitalSource.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * Class to write to digital outputs.
  *
@@ -25,8 +20,8 @@
  * shouldn't be done here.
  */
 class DigitalOutput : public DigitalSource,
-                      public Sendable,
-                      public SendableHelper<DigitalOutput> {
+                      public wpi::Sendable,
+                      public wpi::SendableHelper<DigitalOutput> {
  public:
   /**
    * Create an instance of a digital output.
@@ -148,7 +143,7 @@
    */
   void SetSimDevice(HAL_SimDeviceHandle device);
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   int m_channel;
diff --git a/wpilibc/src/main/native/include/frc/DigitalSource.h b/wpilibc/src/main/native/include/frc/DigitalSource.h
index 5d77daa..0dd35d6 100644
--- a/wpilibc/src/main/native/include/frc/DigitalSource.h
+++ b/wpilibc/src/main/native/include/frc/DigitalSource.h
@@ -1,15 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <hal/Types.h>
 
-#include "frc/InterruptableSensorBase.h"
+#include "frc/AnalogTriggerType.h"
 
 namespace frc {
 
@@ -22,7 +19,7 @@
  * constructed and freed when finished for the source. The source can either be
  * a digital input or analog trigger but not both.
  */
-class DigitalSource : public InterruptableSensorBase {
+class DigitalSource {
  public:
   DigitalSource() = default;
   DigitalSource(DigitalSource&&) = default;
diff --git a/wpilibc/src/main/native/include/frc/DoubleSolenoid.h b/wpilibc/src/main/native/include/frc/DoubleSolenoid.h
index 302c52c..381e3a1 100644
--- a/wpilibc/src/main/native/include/frc/DoubleSolenoid.h
+++ b/wpilibc/src/main/native/include/frc/DoubleSolenoid.h
@@ -1,53 +1,54 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <hal/Types.h>
+#include <memory>
 
-#include "frc/SolenoidBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <hal/Types.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
+#include "frc/PneumaticsBase.h"
+#include "frc/PneumaticsModuleType.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * DoubleSolenoid class for running 2 channels of high voltage Digital Output
- * (PCM).
+ * on a pneumatics module.
  *
  * The DoubleSolenoid class is typically used for pneumatics solenoids that
  * have two positions controlled by two separate channels.
  */
-class DoubleSolenoid : public SolenoidBase,
-                       public Sendable,
-                       public SendableHelper<DoubleSolenoid> {
+class DoubleSolenoid : public wpi::Sendable,
+                       public wpi::SendableHelper<DoubleSolenoid> {
  public:
   enum Value { kOff, kForward, kReverse };
 
   /**
-   * Constructor.
+   * Constructs a double solenoid for a specified module of a specific module
+   * type.
    *
-   * Uses the default PCM ID of 0.
-   *
-   * @param forwardChannel The forward channel number on the PCM (0..7).
-   * @param reverseChannel The reverse channel number on the PCM (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.
    */
-  explicit DoubleSolenoid(int forwardChannel, int reverseChannel);
+  DoubleSolenoid(int module, PneumaticsModuleType moduleType,
+                 int forwardChannel, int reverseChannel);
 
   /**
-   * Constructor.
+   * Constructs a double solenoid for a default module of a specific module
+   * type.
    *
-   * @param moduleNumber   The CAN ID of the PCM.
-   * @param forwardChannel The forward channel on the PCM to control (0..7).
-   * @param reverseChannel The reverse channel on the PCM to control (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.
    */
-  DoubleSolenoid(int moduleNumber, int forwardChannel, int reverseChannel);
+  DoubleSolenoid(PneumaticsModuleType moduleType, int forwardChannel,
+                 int reverseChannel);
 
   ~DoubleSolenoid() override;
 
@@ -78,36 +79,50 @@
   void Toggle();
 
   /**
-   * Check if the forward solenoid is blacklisted.
+   * Get the forward channel.
    *
-   * If a solenoid is shorted, it is added to the blacklist and disabled until
-   * power cycle, or until faults are cleared.
-   *
-   * @see ClearAllPCMStickyFaults()
-   * @return If solenoid is disabled due to short.
+   * @return the forward channel.
    */
-  bool IsFwdSolenoidBlackListed() const;
+  int GetFwdChannel() const;
 
   /**
-   * Check if the reverse solenoid is blacklisted.
+   * Get the reverse channel.
    *
-   * If a solenoid is shorted, it is added to the blacklist and disabled until
-   * power cycle, or until faults are cleared.
+   * @return the reverse channel.
+   */
+  int GetRevChannel() const;
+
+  /**
+   * 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.
    *
    * @see ClearAllPCMStickyFaults()
    * @return If solenoid is disabled due to short.
    */
-  bool IsRevSolenoidBlackListed() const;
+  bool IsFwdSolenoidDisabled() const;
 
-  void InitSendable(SendableBuilder& builder) override;
+  /**
+   * 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.
+   *
+   * @see ClearAllPCMStickyFaults()
+   * @return If solenoid is disabled due to short.
+   */
+  bool IsRevSolenoidDisabled() const;
+
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
+  std::shared_ptr<PneumaticsBase> m_module;
   int m_forwardChannel;  // The forward channel on the module to control.
   int m_reverseChannel;  // The reverse channel on the module to control.
   int m_forwardMask;     // The mask for the forward channel.
   int m_reverseMask;     // The mask for the reverse channel.
-  hal::Handle<HAL_SolenoidHandle> m_forwardHandle;
-  hal::Handle<HAL_SolenoidHandle> m_reverseHandle;
+  int m_mask;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/DriverStation.h b/wpilibc/src/main/native/include/frc/DriverStation.h
index a6c40d6..30bf4fc 100644
--- a/wpilibc/src/main/native/include/frc/DriverStation.h
+++ b/wpilibc/src/main/native/include/frc/DriverStation.h
@@ -1,102 +1,64 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <array>
-#include <atomic>
-#include <memory>
 #include <string>
-#include <thread>
 
-#include <hal/DriverStationTypes.h>
-#include <wpi/Twine.h>
-#include <wpi/condition_variable.h>
-#include <wpi/mutex.h>
-
-#include "frc/ErrorBase.h"
+#include <units/time.h>
+#include <wpi/deprecated.h>
 
 namespace frc {
 
-class MatchDataSender;
-
 /**
  * Provide access to the network communication data to / from the Driver
  * Station.
  */
-class DriverStation : public ErrorBase {
+class DriverStation {
  public:
   enum Alliance { kRed, kBlue, kInvalid };
   enum MatchType { kNone, kPractice, kQualification, kElimination };
 
-  ~DriverStation() override;
-
-  DriverStation(const DriverStation&) = delete;
-  DriverStation& operator=(const DriverStation&) = delete;
-
   /**
    * Return a reference to the singleton DriverStation.
    *
    * @return Reference to the DS instance
+   * @deprecated Use the static methods
    */
+  WPI_DEPRECATED("Use static methods")
   static DriverStation& GetInstance();
 
-  /**
-   * Report an error to the DriverStation messages window.
-   *
-   * The error is also printed to the program console.
-   */
-  static void ReportError(const wpi::Twine& error);
-
-  /**
-   * Report a warning to the DriverStation messages window.
-   *
-   * The warning is also printed to the program console.
-   */
-  static void ReportWarning(const wpi::Twine& error);
-
-  /**
-   * Report an error to the DriverStation messages window.
-   *
-   * The error is also printed to the program console.
-   */
-  static void ReportError(bool isError, int code, const wpi::Twine& error,
-                          const wpi::Twine& location, const wpi::Twine& stack);
-
   static constexpr int kJoystickPorts = 6;
 
   /**
-   * The state of one joystick button. Button indexes begin at 1.
+   * The state of one joystick button. %Button indexes begin at 1.
    *
    * @param stick  The joystick to read.
    * @param button The button index, beginning at 1.
    * @return The state of the joystick button.
    */
-  bool GetStickButton(int stick, int button);
+  static bool GetStickButton(int stick, int button);
 
   /**
-   * Whether one joystick button was pressed since the last check. Button
+   * Whether one joystick button was pressed since the last check. %Button
    * indexes begin at 1.
    *
    * @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.
    */
-  bool GetStickButtonPressed(int stick, int button);
+  static bool GetStickButtonPressed(int stick, int button);
 
   /**
-   * Whether one joystick button was released since the last check. Button
+   * Whether one joystick button was released since the last check. %Button
    * indexes begin at 1.
    *
    * @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.
    */
-  bool GetStickButtonReleased(int stick, int button);
+  static bool GetStickButtonReleased(int stick, int button);
 
   /**
    * Get the value of the axis on a joystick.
@@ -108,14 +70,14 @@
    * @param axis  The analog axis value to read from the joystick.
    * @return The value of the axis on the joystick.
    */
-  double GetStickAxis(int stick, int axis);
+  static double GetStickAxis(int stick, int axis);
 
   /**
    * Get the state of a POV on the joystick.
    *
    * @return the angle of the POV in degrees, or -1 if the POV is not pressed.
    */
-  int GetStickPOV(int stick, int pov);
+  static int GetStickPOV(int stick, int pov);
 
   /**
    * The state of the buttons on the joystick.
@@ -123,7 +85,7 @@
    * @param stick The joystick to read.
    * @return The state of the buttons on the joystick.
    */
-  int GetStickButtons(int stick) const;
+  static int GetStickButtons(int stick);
 
   /**
    * Returns the number of axes on a given joystick port.
@@ -131,7 +93,7 @@
    * @param stick The joystick port number
    * @return The number of axes on the indicated joystick
    */
-  int GetStickAxisCount(int stick) const;
+  static int GetStickAxisCount(int stick);
 
   /**
    * Returns the number of POVs on a given joystick port.
@@ -139,7 +101,7 @@
    * @param stick The joystick port number
    * @return The number of POVs on the indicated joystick
    */
-  int GetStickPOVCount(int stick) const;
+  static int GetStickPOVCount(int stick);
 
   /**
    * Returns the number of buttons on a given joystick port.
@@ -147,7 +109,7 @@
    * @param stick The joystick port number
    * @return The number of buttons on the indicated joystick
    */
-  int GetStickButtonCount(int stick) const;
+  static int GetStickButtonCount(int stick);
 
   /**
    * Returns a boolean indicating if the controller is an xbox controller.
@@ -155,7 +117,7 @@
    * @param stick The joystick port number
    * @return A boolean that is true if the controller is an xbox controller.
    */
-  bool GetJoystickIsXbox(int stick) const;
+  static bool GetJoystickIsXbox(int stick);
 
   /**
    * Returns the type of joystick at a given port.
@@ -163,7 +125,7 @@
    * @param stick The joystick port number
    * @return The HID type of joystick at the given port
    */
-  int GetJoystickType(int stick) const;
+  static int GetJoystickType(int stick);
 
   /**
    * Returns the name of the joystick at the given port.
@@ -171,15 +133,16 @@
    * @param stick The joystick port number
    * @return The name of the joystick at the given port
    */
-  std::string GetJoystickName(int stick) const;
+  static std::string GetJoystickName(int stick);
 
   /**
    * Returns the types of Axes on a given joystick port.
    *
    * @param stick The joystick port number and the target axis
+   * @param axis  The analog axis value to read from the joystick.
    * @return What type of axis the axis is reporting to be
    */
-  int GetJoystickAxisType(int stick, int axis) const;
+  static int GetJoystickAxisType(int stick, int axis);
 
   /**
    * Returns if a joystick is connected to the Driver Station.
@@ -190,35 +153,35 @@
    * @param stick The joystick port number
    * @return true if a joystick is connected
    */
-  bool IsJoystickConnected(int stick) const;
+  static bool IsJoystickConnected(int stick);
 
   /**
    * Check if the DS has enabled the robot.
    *
    * @return True if the robot is enabled and the DS is connected
    */
-  bool IsEnabled() const;
+  static bool IsEnabled();
 
   /**
    * Check if the robot is disabled.
    *
    * @return True if the robot is explicitly disabled or the DS is not connected
    */
-  bool IsDisabled() const;
+  static bool IsDisabled();
 
   /**
    * Check if the robot is e-stopped.
    *
    * @return True if the robot is e-stopped
    */
-  bool IsEStopped() const;
+  static bool IsEStopped();
 
   /**
    * Check if the DS is commanding autonomous mode.
    *
    * @return True if the robot is being commanded to be in autonomous mode
    */
-  bool IsAutonomous() const;
+  static bool IsAutonomous();
 
   /**
    * Check if the DS is commanding autonomous mode and if it has enabled the
@@ -227,14 +190,33 @@
    * @return True if the robot is being commanded to be in autonomous mode and
    * enabled.
    */
-  bool IsAutonomousEnabled() const;
+  static bool IsAutonomousEnabled();
+
+  /**
+   * Check if the DS is commanding teleop mode.
+   *
+   * @return True if the robot is being commanded to be in teleop mode
+   * @deprecated Use IsTeleop() instead.
+   */
+  WPI_DEPRECATED("Use IsTeleop() instead")
+  static bool IsOperatorControl();
 
   /**
    * Check if the DS is commanding teleop mode.
    *
    * @return True if the robot is being commanded to be in teleop mode
    */
-  bool IsOperatorControl() const;
+  static bool IsTeleop();
+
+  /**
+   * Check if the DS is commanding teleop mode and if it has enabled the robot.
+   *
+   * @return True if the robot is being commanded to be in teleop mode and
+   * enabled.
+   * @deprecated Use IsTeleopEnabled() instead.
+   */
+  WPI_DEPRECATED("Use IsTeleopEnabled() instead")
+  static bool IsOperatorControlEnabled();
 
   /**
    * Check if the DS is commanding teleop mode and if it has enabled the robot.
@@ -242,21 +224,21 @@
    * @return True if the robot is being commanded to be in teleop mode and
    * enabled.
    */
-  bool IsOperatorControlEnabled() const;
+  static bool IsTeleopEnabled();
 
   /**
    * Check if the DS is commanding test mode.
    *
    * @return True if the robot is being commanded to be in test mode
    */
-  bool IsTest() const;
+  static bool IsTest();
 
   /**
    * Check if the DS is attached.
    *
    * @return True if the DS is connected to the robot
    */
-  bool IsDSAttached() const;
+  static bool IsDSAttached();
 
   /**
    * Has a new control packet from the driver station arrived since the last
@@ -267,7 +249,7 @@
    *
    * @return True if the control data has been updated since the last call.
    */
-  bool IsNewControlData() const;
+  static bool IsNewControlData();
 
   /**
    * Is the driver station attached to a Field Management System?
@@ -275,21 +257,21 @@
    * @return True if the robot is competing on a field being controlled by a
    *         Field Management System
    */
-  bool IsFMSAttached() const;
+  static bool IsFMSAttached();
 
   /**
    * Returns the game specific message provided by the FMS.
    *
    * @return A string containing the game specific message.
    */
-  std::string GetGameSpecificMessage() const;
+  static std::string GetGameSpecificMessage();
 
   /**
    * Returns the name of the competition event provided by the FMS.
    *
    * @return A string containing the event name
    */
-  std::string GetEventName() const;
+  static std::string GetEventName();
 
   /**
    * Returns the type of match being played provided by the FMS.
@@ -297,14 +279,14 @@
    * @return The match type enum (kNone, kPractice, kQualification,
    *         kElimination)
    */
-  MatchType GetMatchType() const;
+  static MatchType GetMatchType();
 
   /**
    * Returns the match number provided by the FMS.
    *
    * @return The number of the match
    */
-  int GetMatchNumber() const;
+  static int GetMatchNumber();
 
   /**
    * Returns the number of times the current match has been replayed from the
@@ -312,7 +294,7 @@
    *
    * @return The number of replays
    */
-  int GetReplayNumber() const;
+  static int GetReplayNumber();
 
   /**
    * Return the alliance that the driver station says it is on.
@@ -321,7 +303,7 @@
    *
    * @return The Alliance enum (kRed, kBlue or kInvalid)
    */
-  Alliance GetAlliance() const;
+  static Alliance GetAlliance();
 
   /**
    * Return the driver station location on the field.
@@ -330,7 +312,7 @@
    *
    * @return The location of the driver station (1-3, 0 for invalid)
    */
-  int GetLocation() const;
+  static int GetLocation();
 
   /**
    * Wait until a new packet comes from the driver station.
@@ -343,7 +325,7 @@
    * Checks if new control data has arrived since the last waitForData call
    * on the current thread. If new data has not arrived, returns immediately.
    */
-  void WaitForData();
+  static void WaitForData();
 
   /**
    * Wait until a new packet comes from the driver station, or wait for a
@@ -361,11 +343,11 @@
    * This is a good way to delay processing until there is new driver station
    * data to act on.
    *
-   * @param timeout Timeout time in seconds
+   * @param timeout Timeout
    *
    * @return true if new data, otherwise false
    */
-  bool WaitForData(double timeout);
+  static bool WaitForData(units::second_t timeout);
 
   /**
    * Return the approximate match time.
@@ -382,14 +364,14 @@
    *
    * @return Time remaining in current match period (auto or teleop)
    */
-  double GetMatchTime() const;
+  static double GetMatchTime();
 
   /**
    * Read the battery voltage.
    *
    * @return The battery voltage in Volts.
    */
-  double GetBatteryVoltage() const;
+  static double GetBatteryVoltage();
 
   /**
    * Only to be used to tell the Driver Station what code you claim to be
@@ -398,7 +380,7 @@
    * @param entering If true, starting disabled code; if false, leaving disabled
    *                 code.
    */
-  void InDisabled(bool entering) { m_userInDisabled = entering; }
+  static void InDisabled(bool entering);
 
   /**
    * Only to be used to tell the Driver Station what code you claim to be
@@ -407,7 +389,18 @@
    * @param entering If true, starting autonomous code; if false, leaving
    *                 autonomous code.
    */
-  void InAutonomous(bool entering) { m_userInAutonomous = entering; }
+  static void InAutonomous(bool 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.
+   * @deprecated Use InTeleop() instead.
+   */
+  WPI_DEPRECATED("Use InTeleop() instead")
+  static void InOperatorControl(bool entering);
 
   /**
    * Only to be used to tell the Driver Station what code you claim to be
@@ -416,7 +409,7 @@
    * @param entering If true, starting teleop code; if false, leaving teleop
    *                 code.
    */
-  void InOperatorControl(bool entering) { m_userInTeleop = entering; }
+  static void InTeleop(bool entering);
 
   /**
    * Only to be used to tell the Driver Station what code you claim to be
@@ -424,12 +417,12 @@
    *
    * @param entering If true, starting test code; if false, leaving test code.
    */
-  void InTest(bool entering) { m_userInTest = entering; }
+  static void InTest(bool entering);
 
   /**
    * Forces WaitForData() to return immediately.
    */
-  void WakeupWaitForData();
+  static void WakeupWaitForData();
 
   /**
    * Allows the user to specify whether they want joystick connection warnings
@@ -438,7 +431,7 @@
    *
    * @param silence Whether warning messages should be silenced.
    */
-  void SilenceJoystickConnectionWarning(bool silence);
+  static void SilenceJoystickConnectionWarning(bool silence);
 
   /**
    * Returns whether joystick connection warnings are silenced. This will
@@ -446,68 +439,10 @@
    *
    * @return Whether joystick connection warnings are silenced.
    */
-  bool IsJoystickConnectionWarningSilenced() const;
-
- protected:
-  /**
-   * 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.
-   */
-  void GetData();
+  static bool IsJoystickConnectionWarningSilenced();
 
  private:
-  /**
-   * DriverStation constructor.
-   *
-   * This is only called once the first time GetInstance() is called
-   */
-  DriverStation();
-
-  /**
-   * Reports errors related to unplugged joysticks.
-   *
-   * Throttles the errors so that they don't overwhelm the DS.
-   */
-  void ReportJoystickUnpluggedError(const wpi::Twine& message);
-
-  /**
-   * Reports errors related to unplugged joysticks.
-   *
-   * Throttles the errors so that they don't overwhelm the DS.
-   */
-  void ReportJoystickUnpluggedWarning(const wpi::Twine& message);
-
-  void Run();
-
-  void SendMatchData();
-
-  std::unique_ptr<MatchDataSender> m_matchDataSender;
-
-  // Joystick button rising/falling edge flags
-  wpi::mutex m_buttonEdgeMutex;
-  std::array<HAL_JoystickButtons, kJoystickPorts> m_previousButtonStates;
-  std::array<uint32_t, kJoystickPorts> m_joystickButtonsPressed;
-  std::array<uint32_t, kJoystickPorts> m_joystickButtonsReleased;
-
-  // Internal Driver Station thread
-  std::thread m_dsThread;
-  std::atomic<bool> m_isRunning{false};
-
-  mutable wpi::mutex m_waitForDataMutex;
-  wpi::condition_variable m_waitForDataCond;
-  int m_waitForDataCounter;
-
-  bool m_silenceJoystickWarning = false;
-
-  // Robot state status variables
-  bool m_userInDisabled = false;
-  bool m_userInAutonomous = false;
-  bool m_userInTeleop = false;
-  bool m_userInTest = false;
-
-  double m_nextMessageTime = 0;
+  DriverStation() = default;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/DutyCycle.h b/wpilibc/src/main/native/include/frc/DutyCycle.h
index f0fc2d8..7f45d06 100644
--- a/wpilibc/src/main/native/include/frc/DutyCycle.h
+++ b/wpilibc/src/main/native/include/frc/DutyCycle.h
@@ -1,19 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
 
 #include <hal/Types.h>
-
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 namespace frc {
 class DigitalSource;
@@ -32,9 +27,7 @@
  * order to implement rollover checking.
  *
  */
-class DutyCycle : public ErrorBase,
-                  public Sendable,
-                  public SendableHelper<DutyCycle> {
+class DutyCycle : public wpi::Sendable, public wpi::SendableHelper<DutyCycle> {
   friend class AnalogTrigger;
   friend class DMA;
   friend class DMASample;
@@ -125,7 +118,7 @@
   int GetSourceChannel() const;
 
  protected:
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   void InitDutyCycle();
diff --git a/wpilibc/src/main/native/include/frc/DutyCycleEncoder.h b/wpilibc/src/main/native/include/frc/DutyCycleEncoder.h
index 17b038f..ccf56ad 100644
--- a/wpilibc/src/main/native/include/frc/DutyCycleEncoder.h
+++ b/wpilibc/src/main/native/include/frc/DutyCycleEncoder.h
@@ -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.
 
 #pragma once
 
@@ -12,12 +9,11 @@
 #include <hal/SimDevice.h>
 #include <hal/Types.h>
 #include <units/angle.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/AnalogTrigger.h"
 #include "frc/Counter.h"
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 class DutyCycle;
@@ -28,9 +24,8 @@
  * PWM Output, the CTRE Mag Encoder, the Rev Hex Encoder, and the AM Mag
  * Encoder.
  */
-class DutyCycleEncoder : public ErrorBase,
-                         public Sendable,
-                         public SendableHelper<DutyCycleEncoder> {
+class DutyCycleEncoder : public wpi::Sendable,
+                         public wpi::SendableHelper<DutyCycleEncoder> {
  public:
   /**
    * Construct a new DutyCycleEncoder on a specific channel.
@@ -63,21 +58,21 @@
   /**
    * Construct a new DutyCycleEncoder attached to a DigitalSource object.
    *
-   * @param source the digital source to attach to
+   * @param digitalSource the digital source to attach to
    */
   explicit DutyCycleEncoder(DigitalSource& digitalSource);
 
   /**
    * Construct a new DutyCycleEncoder attached to a DigitalSource object.
    *
-   * @param source the digital source to attach to
+   * @param digitalSource the digital source to attach to
    */
   explicit DutyCycleEncoder(DigitalSource* digitalSource);
 
   /**
    * Construct a new DutyCycleEncoder attached to a DigitalSource object.
    *
-   * @param source the digital source to attach to
+   * @param digitalSource the digital source to attach to
    */
   explicit DutyCycleEncoder(std::shared_ptr<DigitalSource> digitalSource);
 
@@ -168,7 +163,7 @@
    */
   int GetSourceChannel() const;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   void Init();
diff --git a/wpilibc/src/main/native/include/frc/Encoder.h b/wpilibc/src/main/native/include/frc/Encoder.h
index 76f9d1c..f6753c2 100644
--- a/wpilibc/src/main/native/include/frc/Encoder.h
+++ b/wpilibc/src/main/native/include/frc/Encoder.h
@@ -1,28 +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.
 
 #pragma once
 
 #include <memory>
 
 #include <hal/Types.h>
+#include <wpi/deprecated.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/Counter.h"
 #include "frc/CounterBase.h"
-#include "frc/ErrorBase.h"
-#include "frc/PIDSource.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
 class DigitalSource;
 class DigitalGlitchFilter;
-class SendableBuilder;
 class DMA;
 class DMASample;
 
@@ -41,11 +36,9 @@
  * All encoders will immediately start counting - Reset() them if you need them
  * to be zeroed before use.
  */
-class Encoder : public ErrorBase,
-                public CounterBase,
-                public PIDSource,
-                public Sendable,
-                public SendableHelper<Encoder> {
+class Encoder : public CounterBase,
+                public wpi::Sendable,
+                public wpi::SendableHelper<Encoder> {
   friend class DMA;
   friend class DMASample;
 
@@ -174,7 +167,7 @@
    *
    * @return Period in seconds of the most recent pulse.
    */
-  double GetPeriod() const override;
+  units::second_t GetPeriod() const override;
 
   /**
    * Sets the maximum period for stopped detection.
@@ -195,7 +188,7 @@
   WPI_DEPRECATED(
       "Use SetMinRate() in favor of this method.  This takes unscaled periods "
       "and SetMinRate() scales using value from SetDistancePerPulse().")
-  void SetMaxPeriod(double maxPeriod) override;
+  void SetMaxPeriod(units::second_t maxPeriod) override;
 
   /**
    * Determine if the encoder is stopped.
@@ -317,8 +310,6 @@
    */
   int GetSamplesToAverage() const;
 
-  double PIDGet() override;
-
   /**
    * Set the index source for the encoder.
    *
@@ -334,8 +325,8 @@
    *
    * When this source is activated, the encoder count automatically resets.
    *
-   * @param channel A digital source to set as the encoder index
-   * @param type    The state that will cause the encoder to reset
+   * @param source A digital source to set as the encoder index
+   * @param type   The state that will cause the encoder to reset
    */
   void SetIndexSource(const DigitalSource& source,
                       IndexingType type = kResetOnRisingEdge);
@@ -349,7 +340,7 @@
 
   int GetFPGAIndex() const;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   /**
diff --git a/wpilibc/src/main/native/include/frc/Error.h b/wpilibc/src/main/native/include/frc/Error.h
deleted file mode 100644
index d63fb62..0000000
--- a/wpilibc/src/main/native/include/frc/Error.h
+++ /dev/null
@@ -1,66 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <string>
-
-#include <wpi/StringRef.h>
-#include <wpi/Twine.h>
-
-#ifdef _WIN32
-#pragma push_macro("GetMessage")
-#undef GetMessage
-#endif
-
-namespace frc {
-
-class ErrorBase;
-
-/**
- * Error object represents a library error.
- */
-class Error {
- public:
-  using Code = int;
-
-  Error() = default;
-  Error(Code code, const wpi::Twine& contextMessage, wpi::StringRef filename,
-        wpi::StringRef function, int lineNumber,
-        const ErrorBase* originatingObject);
-
-  bool operator<(const Error& rhs) const;
-
-  Code GetCode() const;
-  std::string GetMessage() const;
-  std::string GetFilename() const;
-  std::string GetFunction() const;
-  int GetLineNumber() const;
-  const ErrorBase* GetOriginatingObject() const;
-  double GetTimestamp() const;
-  void Clear();
-  void Set(Code code, const wpi::Twine& contextMessage, wpi::StringRef filename,
-           wpi::StringRef function, int lineNumber,
-           const ErrorBase* originatingObject);
-
- private:
-  void Report();
-
-  Code m_code = 0;
-  std::string m_message;
-  std::string m_filename;
-  std::string m_function;
-  int m_lineNumber = 0;
-  const ErrorBase* m_originatingObject = nullptr;
-  double m_timestamp = 0.0;
-};
-
-}  // namespace frc
-
-#ifdef _WIN32
-#pragma pop_macro("GetMessage")
-#endif
diff --git a/wpilibc/src/main/native/include/frc/ErrorBase.h b/wpilibc/src/main/native/include/frc/ErrorBase.h
deleted file mode 100644
index 0ced9a2..0000000
--- a/wpilibc/src/main/native/include/frc/ErrorBase.h
+++ /dev/null
@@ -1,242 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <vector>
-
-#include <wpi/StringRef.h>
-#include <wpi/Twine.h>
-
-#include "frc/Error.h"
-
-// Forward declared manually to avoid needing to pull in entire HAL header.
-extern "C" const char* HAL_GetErrorMessage(int32_t code);
-
-#define wpi_setErrnoErrorWithContext(context) \
-  this->SetErrnoError((context), __FILE__, __FUNCTION__, __LINE__)
-#define wpi_setErrnoError() wpi_setErrnoErrorWithContext("")
-#define wpi_setImaqErrorWithContext(code, context)                             \
-  do {                                                                         \
-    if ((code) != 0)                                                           \
-      this->SetImaqError((code), (context), __FILE__, __FUNCTION__, __LINE__); \
-  } while (0)
-#define wpi_setErrorWithContext(code, context)                             \
-  do {                                                                     \
-    if ((code) != 0)                                                       \
-      this->SetError((code), (context), __FILE__, __FUNCTION__, __LINE__); \
-  } while (0)
-#define wpi_setErrorWithContextRange(code, min, max, req, context)          \
-  do {                                                                      \
-    if ((code) != 0)                                                        \
-      this->SetErrorRange((code), (min), (max), (req), (context), __FILE__, \
-                          __FUNCTION__, __LINE__);                          \
-  } while (0)
-
-#define wpi_setHALError(code)                                     \
-  do {                                                            \
-    if ((code) != 0)                                              \
-      this->SetError((code), HAL_GetErrorMessage(code), __FILE__, \
-                     __FUNCTION__, __LINE__);                     \
-  } while (0)
-
-#define wpi_setHALErrorWithRange(code, min, max, req)                        \
-  do {                                                                       \
-    if ((code) != 0)                                                         \
-      this->SetErrorRange((code), (min), (max), (req),                       \
-                          HAL_GetErrorMessage(code), __FILE__, __FUNCTION__, \
-                          __LINE__);                                         \
-  } while (0)
-
-#define wpi_setError(code) wpi_setErrorWithContext(code, "")
-#define wpi_setStaticErrorWithContext(object, code, context)                 \
-  do {                                                                       \
-    if ((code) != 0)                                                         \
-      object->SetError((code), (context), __FILE__, __FUNCTION__, __LINE__); \
-  } while (0)
-#define wpi_setStaticError(object, code) \
-  wpi_setStaticErrorWithContext(object, code, "")
-
-#define wpi_setGlobalErrorWithContext(code, context)                \
-  do {                                                              \
-    if ((code) != 0)                                                \
-      ::frc::ErrorBase::SetGlobalError((code), (context), __FILE__, \
-                                       __FUNCTION__, __LINE__);     \
-  } while (0)
-
-#define wpi_setGlobalHALError(code)                                       \
-  do {                                                                    \
-    if ((code) != 0)                                                      \
-      ::frc::ErrorBase::SetGlobalError((code), HAL_GetErrorMessage(code), \
-                                       __FILE__, __FUNCTION__, __LINE__); \
-  } while (0)
-
-#define wpi_setGlobalError(code) wpi_setGlobalErrorWithContext(code, "")
-#define wpi_setWPIErrorWithContext(error, context)                    \
-  this->SetWPIError(wpi_error_s_##error(), wpi_error_value_##error(), \
-                    (context), __FILE__, __FUNCTION__, __LINE__)
-#define wpi_setWPIError(error) (wpi_setWPIErrorWithContext(error, ""))
-#define wpi_setStaticWPIErrorWithContext(object, error, context)  \
-  object->SetWPIError(wpi_error_s_##error(), (context), __FILE__, \
-                      __FUNCTION__, __LINE__)
-#define wpi_setStaticWPIError(object, error) \
-  wpi_setStaticWPIErrorWithContext(object, error, "")
-#define wpi_setGlobalWPIErrorWithContext(error, context)                \
-  ::frc::ErrorBase::SetGlobalWPIError(wpi_error_s_##error(), (context), \
-                                      __FILE__, __FUNCTION__, __LINE__)
-#define wpi_setGlobalWPIError(error) wpi_setGlobalWPIErrorWithContext(error, "")
-
-namespace frc {
-
-/**
- * Base class for most objects.
- *
- * ErrorBase is the base class for most objects since it holds the generated
- * error for that object. In addition, there is a single instance of a global
- * error object.
- */
-class ErrorBase {
-  // TODO: Consider initializing instance variables and cleanup in destructor
- public:
-  ErrorBase();
-  virtual ~ErrorBase() = default;
-
-  ErrorBase(const ErrorBase&) = default;
-  ErrorBase& operator=(const ErrorBase&) = default;
-  ErrorBase(ErrorBase&&) = default;
-  ErrorBase& operator=(ErrorBase&&) = default;
-
-  /**
-   * @brief Retrieve the current error.
-   *
-   * Get the current error information associated with this sensor.
-   */
-  virtual Error& GetError();
-
-  /**
-   * @brief Retrieve the current error.
-   *
-   * Get the current error information associated with this sensor.
-   */
-  virtual const Error& GetError() const;
-
-  /**
-   * @brief Clear the current error information associated with this sensor.
-   */
-  virtual void ClearError() const;
-
-  /**
-   * @brief Set error information associated with a C library call that set an
-   *        error to the "errno" global variable.
-   *
-   * @param contextMessage A custom message from the code that set the error.
-   * @param filename       Filename of the error source
-   * @param function       Function of the error source
-   * @param lineNumber     Line number of the error source
-   */
-  virtual void SetErrnoError(const wpi::Twine& contextMessage,
-                             wpi::StringRef filename, wpi::StringRef function,
-                             int lineNumber) const;
-
-  /**
-   * @brief Set the current error information associated from the nivision Imaq
-   *        API.
-   *
-   * @param success        The return from the function
-   * @param contextMessage A custom message from the code that set the error.
-   * @param filename       Filename of the error source
-   * @param function       Function of the error source
-   * @param lineNumber     Line number of the error source
-   */
-  virtual void SetImaqError(int success, const wpi::Twine& contextMessage,
-                            wpi::StringRef filename, wpi::StringRef function,
-                            int lineNumber) const;
-
-  /**
-   * @brief Set the current error information associated with this sensor.
-   *
-   * @param code           The error code
-   * @param contextMessage A custom message from the code that set the error.
-   * @param filename       Filename of the error source
-   * @param function       Function of the error source
-   * @param lineNumber     Line number of the error source
-   */
-  virtual void SetError(Error::Code code, const wpi::Twine& contextMessage,
-                        wpi::StringRef filename, wpi::StringRef function,
-                        int lineNumber) const;
-
-  /**
-   * @brief Set the current error information associated with this sensor.
-   * Range versions use for initialization code.
-   *
-   * @param code           The error code
-   * @param minRange       The minimum allowed allocation range
-   * @param maxRange       The maximum allowed allocation range
-   * @param requestedValue The requested value to allocate
-   * @param contextMessage A custom message from the code that set the error.
-   * @param filename       Filename of the error source
-   * @param function       Function of the error source
-   * @param lineNumber     Line number of the error source
-   */
-  virtual void SetErrorRange(Error::Code code, int32_t minRange,
-                             int32_t maxRange, int32_t requestedValue,
-                             const wpi::Twine& contextMessage,
-                             wpi::StringRef filename, wpi::StringRef function,
-                             int lineNumber) const;
-
-  /**
-   * @brief Set the current error information associated with this sensor.
-   *
-   * @param errorMessage   The error message from WPIErrors.h
-   * @param contextMessage A custom message from the code that set the error.
-   * @param filename       Filename of the error source
-   * @param function       Function of the error source
-   * @param lineNumber     Line number of the error source
-   */
-  virtual void SetWPIError(const wpi::Twine& errorMessage, Error::Code code,
-                           const wpi::Twine& contextMessage,
-                           wpi::StringRef filename, wpi::StringRef function,
-                           int lineNumber) const;
-
-  virtual void CloneError(const ErrorBase& rhs) const;
-
-  /**
-   * @brief Check if the current error code represents a fatal error.
-   *
-   * @return true if the current error is fatal.
-   */
-  virtual bool StatusIsFatal() const;
-
-  static void SetGlobalError(Error::Code code, const wpi::Twine& contextMessage,
-                             wpi::StringRef filename, wpi::StringRef function,
-                             int lineNumber);
-
-  static void SetGlobalWPIError(const wpi::Twine& errorMessage,
-                                const wpi::Twine& contextMessage,
-                                wpi::StringRef filename,
-                                wpi::StringRef function, int lineNumber);
-
-  /**
-   * Retrieve the last global error.
-   */
-  static Error GetGlobalError();
-
-  /**
-   * Retrieve all global errors.
-   */
-  static std::vector<Error> GetGlobalErrors();
-
-  /**
-   * Clear global errors.
-   */
-  void ClearGlobalErrors();
-
- protected:
-  mutable Error m_error;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Errors.h b/wpilibc/src/main/native/include/frc/Errors.h
new file mode 100644
index 0000000..84edc18
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/Errors.h
@@ -0,0 +1,177 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+#include <fmt/format.h>
+
+namespace frc {
+
+/**
+ * Runtime error exception.
+ */
+class RuntimeError : public std::runtime_error {
+ public:
+  RuntimeError(int32_t code, std::string&& loc, std::string&& stack,
+               std::string&& message);
+  RuntimeError(int32_t code, const char* fileName, int lineNumber,
+               const char* funcName, std::string&& stack,
+               std::string&& message);
+
+  int32_t code() const noexcept { return m_data->code; }
+  const char* loc() const noexcept { return m_data->loc.c_str(); }
+  const char* stack() const noexcept { return m_data->stack.c_str(); }
+
+  /**
+   * Reports error to Driver Station (using HAL_SendError).
+   */
+  void Report() const;
+
+ private:
+  struct Data {
+    int32_t code;
+    std::string loc;
+    std::string stack;
+  };
+  std::shared_ptr<Data> m_data;
+};
+
+/**
+ * Gets error message string for an error code.
+ */
+const char* GetErrorMessage(int32_t* code);
+
+/**
+ * Reports an error to the driver station (using HAL_SendError).
+ * Generally the FRC_ReportError wrapper macro should be used instead.
+ *
+ * @param[out] status error code
+ * @param[in]  fileName source file name
+ * @param[in]  lineNumber source line number
+ * @param[in]  funcName source function name
+ * @param[in]  format error message format
+ * @param[in]  args error message format args
+ */
+void ReportErrorV(int32_t status, const char* fileName, int lineNumber,
+                  const char* funcName, fmt::string_view format,
+                  fmt::format_args args);
+
+/**
+ * Reports an error to the driver station (using HAL_SendError).
+ * Generally the FRC_ReportError wrapper macro should be used instead.
+ *
+ * @param[out] status error code
+ * @param[in]  fileName source file name
+ * @param[in]  lineNumber source line number
+ * @param[in]  funcName source function name
+ * @param[in]  format error message format
+ * @param[in]  args error message format args
+ */
+template <typename S, typename... Args>
+inline void ReportError(int32_t status, const char* fileName, int lineNumber,
+                        const char* funcName, const S& format, Args&&... args) {
+  ReportErrorV(status, fileName, lineNumber, funcName, format,
+               fmt::make_args_checked<Args...>(format, args...));
+}
+
+/**
+ * Makes a runtime error exception object. This object should be thrown
+ * by the caller. Generally the FRC_MakeError wrapper macro should be used
+ * instead.
+ *
+ * @param[out] status error code
+ * @param[in]  fileName source file name
+ * @param[in]  lineNumber source line number
+ * @param[in]  funcName source function name
+ * @param[in]  format error message format
+ * @param[in]  args error message format args
+ * @return runtime error object
+ */
+[[nodiscard]] RuntimeError MakeErrorV(int32_t status, const char* fileName,
+                                      int lineNumber, const char* funcName,
+                                      fmt::string_view format,
+                                      fmt::format_args args);
+
+template <typename S, typename... Args>
+[[nodiscard]] inline RuntimeError MakeError(int32_t status,
+                                            const char* fileName,
+                                            int lineNumber,
+                                            const char* funcName,
+                                            const S& format, Args&&... args) {
+  return MakeErrorV(status, fileName, lineNumber, funcName, format,
+                    fmt::make_args_checked<Args...>(format, args...));
+}
+
+namespace err {
+#define S(label, offset, message) inline constexpr int label = offset;
+#include "frc/WPIErrors.mac"
+#undef S
+}  // namespace err
+
+namespace warn {
+#define S(label, offset, message) inline constexpr int label = offset;
+#include "frc/WPIWarnings.mac"
+#undef S
+}  // namespace warn
+}  // namespace frc
+
+/**
+ * Reports an error to the driver station (using HAL_SendError).
+ *
+ * @param[out] status error code
+ * @param[in]  format error message format
+ */
+#define FRC_ReportError(status, format, ...)                       \
+  do {                                                             \
+    if ((status) != 0) {                                           \
+      ::frc::ReportError(status, __FILE__, __LINE__, __FUNCTION__, \
+                         FMT_STRING(format), __VA_ARGS__);         \
+    }                                                              \
+  } while (0)
+
+/**
+ * Makes a runtime error exception object. This object should be thrown
+ * by the caller.
+ *
+ * @param[out] status error code
+ * @param[in]  format error message format
+ * @return runtime error object
+ */
+#define FRC_MakeError(status, format, ...)                   \
+  ::frc::MakeError(status, __FILE__, __LINE__, __FUNCTION__, \
+                   FMT_STRING(format), __VA_ARGS__)
+
+/**
+ * Checks a status code and depending on its value, either throws a
+ * RuntimeError exception, calls ReportError, or does nothing (if no error).
+ *
+ * @param[out] status error code
+ * @param[in]  format error message format
+ */
+#define FRC_CheckErrorStatus(status, format, ...)                      \
+  do {                                                                 \
+    if ((status) < 0) {                                                \
+      throw ::frc::MakeError(status, __FILE__, __LINE__, __FUNCTION__, \
+                             FMT_STRING(format), __VA_ARGS__);         \
+    } else if ((status) > 0) {                                         \
+      ::frc::ReportError(status, __FILE__, __LINE__, __FUNCTION__,     \
+                         FMT_STRING(format), __VA_ARGS__);             \
+    }                                                                  \
+  } while (0)
+
+#define FRC_AssertMessage(condition, format, ...)                            \
+  do {                                                                       \
+    if (!(condition)) {                                                      \
+      throw ::frc::MakeError(err::AssertionFailure, __FILE__, __LINE__,      \
+                             __FUNCTION__, FMT_STRING(format), __VA_ARGS__); \
+    }                                                                        \
+  } while (0)
+
+#define FRC_Assert(condition) FRC_AssertMessage(condition, "{}", #condition)
diff --git a/wpilibc/src/main/native/include/frc/Filesystem.h b/wpilibc/src/main/native/include/frc/Filesystem.h
index f196f7a..fbfc681 100644
--- a/wpilibc/src/main/native/include/frc/Filesystem.h
+++ b/wpilibc/src/main/native/include/frc/Filesystem.h
@@ -1,34 +1,30 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/SmallVector.h>
+#include <string>
 
-namespace frc {
 /** WPILib FileSystem namespace */
-namespace filesystem {
+namespace frc::filesystem {
 
 /**
  * Obtains the current working path that the program was launched with.
  * This is analogous to the `pwd` command on unix.
  *
- * @param result The result of the current working path lookup.
+ * @return The result of the current working path lookup.
  */
-void GetLaunchDirectory(wpi::SmallVectorImpl<char>& result);
+std::string GetLaunchDirectory();
 
 /**
  * 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`).
  *
- * @param result The result of the operating directory lookup.
+ * @return The result of the operating directory lookup.
  */
-void GetOperatingDirectory(wpi::SmallVectorImpl<char>& result);
+std::string GetOperatingDirectory();
 
 /**
  * Obtains the deploy directory of the program, which is the remote location
@@ -36,9 +32,8 @@
  * /home/lvuser/deploy. In simulation, it is where the simulation was launched
  * from, in the subdirectory "src/main/deploy" (`pwd`/src/main/deploy).
  *
- * @param result The result of the operating directory lookup
+ * @return The result of the operating directory lookup
  */
-void GetDeployDirectory(wpi::SmallVectorImpl<char>& result);
+std::string GetDeployDirectory();
 
-}  // namespace filesystem
-}  // namespace frc
+}  // namespace frc::filesystem
diff --git a/wpilibc/src/main/native/include/frc/GearTooth.h b/wpilibc/src/main/native/include/frc/GearTooth.h
deleted file mode 100644
index 2d1f792..0000000
--- a/wpilibc/src/main/native/include/frc/GearTooth.h
+++ /dev/null
@@ -1,88 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include <wpi/deprecated.h>
-
-#include "frc/Counter.h"
-
-namespace frc {
-
-/**
- * Alias for counter class.
- *
- * Implements 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 No longer used per FMS usage reporting
- */
-class GearTooth : public Counter {
- public:
-  // 55 uSec for threshold
-  static constexpr double kGearToothThreshold = 55e-6;
-
-  /**
-   * 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.
-   * @param directionSensitive True to enable the pulse length decoding in
-   *                           hardware to specify count direction.
-   */
-  WPI_DEPRECATED(
-      "The only sensor this works with is no longer available and no teams use "
-      "it according to FMS usage reporting.")
-  explicit GearTooth(int channel, bool directionSensitive = false);
-
-  /**
-   * Construct a GearTooth sensor given a digital input.
-   *
-   * This should be used when sharing digital inputs.
-   *
-   * @param source             A pointer to the existing DigitalSource object
-   *                           (such as a DigitalInput)
-   * @param directionSensitive True to enable the pulse length decoding in
-   *                           hardware to specify count direction.
-   */
-  WPI_DEPRECATED(
-      "The only sensor this works with is no longer available and no teams use "
-      "it according to FMS usage reporting.")
-  explicit GearTooth(DigitalSource* source, bool directionSensitive = false);
-
-  /**
-   * Construct a GearTooth sensor given a digital input.
-   *
-   * This should be used when sharing digital inputs.
-   *
-   * @param source             A reference to the existing DigitalSource object
-   *                           (such as a DigitalInput)
-   * @param directionSensitive True to enable the pulse length decoding in
-   *                           hardware to specify count direction.
-   */
-  WPI_DEPRECATED(
-      "The only sensor this works with is no longer available and no teams use "
-      "it according to FMS usage reporting.")
-  explicit GearTooth(std::shared_ptr<DigitalSource> source,
-                     bool directionSensitive = false);
-
-  GearTooth(GearTooth&&) = default;
-  GearTooth& operator=(GearTooth&&) = default;
-
-  /**
-   * Common code called by the constructors.
-   */
-  void EnableDirectionSensing(bool directionSensitive);
-
-  void InitSendable(SendableBuilder& builder) override;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/GenericHID.h b/wpilibc/src/main/native/include/frc/GenericHID.h
index 001b984..b6c18d3 100644
--- a/wpilibc/src/main/native/include/frc/GenericHID.h
+++ b/wpilibc/src/main/native/include/frc/GenericHID.h
@@ -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.
 
 #pragma once
 
@@ -11,16 +8,19 @@
 
 #include <string>
 
-#include "frc/ErrorBase.h"
-
 namespace frc {
 
 class DriverStation;
 
 /**
- * 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.
  */
-class GenericHID : public ErrorBase {
+class GenericHID {
  public:
   enum RumbleType { kLeftRumble, kRightRumble };
 
@@ -44,17 +44,12 @@
     kHID1stPerson = 24
   };
 
-  enum JoystickHand { kLeftHand = 0, kRightHand = 1 };
-
   explicit GenericHID(int port);
   virtual ~GenericHID() = default;
 
   GenericHID(GenericHID&&) = default;
   GenericHID& operator=(GenericHID&&) = default;
 
-  virtual double GetX(JoystickHand hand = kRightHand) const = 0;
-  virtual double GetY(JoystickHand hand = kRightHand) const = 0;
-
   /**
    * Get the button value (starting at button 1).
    *
@@ -71,7 +66,7 @@
   bool GetRawButton(int button) const;
 
   /**
-   * Whether the button was pressed since the last check. Button indexes begin
+   * Whether the button was pressed since the last check. %Button indexes begin
    * at 1.
    *
    * This method returns true if the button went from not pressed to held down
@@ -84,7 +79,7 @@
   bool GetRawButtonPressed(int button);
 
   /**
-   * Whether the button was released since the last check. Button indexes begin
+   * Whether the button was released since the last check. %Button indexes begin
    * at 1.
    *
    * This method returns true if the button went from held down to not pressed
@@ -197,7 +192,6 @@
   void SetRumble(RumbleType type, double value);
 
  private:
-  DriverStation* m_ds;
   int m_port;
   int m_outputs = 0;
   uint16_t m_leftRumble = 0;
diff --git a/wpilibc/src/main/native/include/frc/GyroBase.h b/wpilibc/src/main/native/include/frc/GyroBase.h
deleted file mode 100644
index 037686f..0000000
--- a/wpilibc/src/main/native/include/frc/GyroBase.h
+++ /dev/null
@@ -1,44 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/ErrorBase.h"
-#include "frc/PIDSource.h"
-#include "frc/interfaces/Gyro.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
-
-namespace frc {
-
-/**
- * GyroBase is the common base class for Gyro implementations such as
- * AnalogGyro.
- */
-class GyroBase : public Gyro,
-                 public ErrorBase,
-                 public PIDSource,
-                 public Sendable,
-                 public SendableHelper<GyroBase> {
- public:
-  GyroBase() = default;
-  GyroBase(GyroBase&&) = default;
-  GyroBase& operator=(GyroBase&&) = default;
-
-  // PIDSource interface
-  /**
-   * Get the PIDOutput for the PIDSource base object. Can be set to return
-   * angle or rate using SetPIDSourceType(). Defaults to angle.
-   *
-   * @return The PIDOutput (angle or rate, defaults to angle)
-   */
-  double PIDGet() override;
-
-  void InitSendable(SendableBuilder& builder) override;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/I2C.h b/wpilibc/src/main/native/include/frc/I2C.h
index 2f12615..d874a46 100644
--- a/wpilibc/src/main/native/include/frc/I2C.h
+++ b/wpilibc/src/main/native/include/frc/I2C.h
@@ -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.
 
 #pragma once
 
@@ -11,8 +8,6 @@
 
 #include <hal/I2CTypes.h>
 
-#include "frc/ErrorBase.h"
-
 namespace frc {
 
 /**
@@ -21,7 +16,7 @@
  * This class is intended to be used by sensor (and other I2C device) drivers.
  * It probably should not be used directly.
  */
-class I2C : public ErrorBase {
+class I2C {
  public:
   enum Port { kOnboard = 0, kMXP };
 
@@ -33,11 +28,14 @@
    */
   I2C(Port port, int deviceAddress);
 
-  ~I2C() override;
+  ~I2C();
 
   I2C(I2C&&) = default;
   I2C& operator=(I2C&&) = default;
 
+  Port GetPort() const;
+  int GetDeviceAddress() const;
+
   /**
    * Generic transaction.
    *
@@ -100,7 +98,7 @@
    *
    * @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
+   * @param data            A pointer to the array of bytes to store the data
    *                        read from the device.
    * @return Transfer Aborted... false for success, true for aborted.
    */
diff --git a/wpilibc/src/main/native/include/frc/InterruptableSensorBase.h b/wpilibc/src/main/native/include/frc/InterruptableSensorBase.h
deleted file mode 100644
index 42b7434..0000000
--- a/wpilibc/src/main/native/include/frc/InterruptableSensorBase.h
+++ /dev/null
@@ -1,151 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <functional>
-#include <memory>
-
-#include <hal/Interrupts.h>
-
-#include "frc/AnalogTriggerType.h"
-#include "frc/ErrorBase.h"
-
-namespace frc {
-
-class InterruptableSensorBase : public ErrorBase {
- public:
-  enum WaitResult {
-    kTimeout = 0x0,
-    kRisingEdge = 0x1,
-    kFallingEdge = 0x100,
-    kBoth = 0x101,
-  };
-
-  /**
-   * Handler for interrupts.
-   *
-   * First parameter is if rising, 2nd is if falling.
-   */
-  using InterruptEventHandler = std::function<void(WaitResult)>;
-
-  InterruptableSensorBase() = default;
-
-  /**
-   * Free the resources for an interrupt event.
-   */
-  virtual ~InterruptableSensorBase();
-
-  InterruptableSensorBase(InterruptableSensorBase&&) = default;
-  InterruptableSensorBase& operator=(InterruptableSensorBase&&) = default;
-
-  virtual HAL_Handle GetPortHandleForRouting() const = 0;
-  virtual AnalogTriggerType GetAnalogTriggerTypeForRouting() const = 0;
-
-  /**
-   * Request one of the 8 interrupts asynchronously on this digital input.
-   *
-   * Request interrupts in asynchronous mode where the user's interrupt handler
-   * will be called when the interrupt fires. Users that want control over the
-   * thread priority should use the synchronous method with their own spawned
-   * thread. The default is interrupt on rising edges only.
-   */
-  virtual void RequestInterrupts(HAL_InterruptHandlerFunction handler,
-                                 void* param);
-
-  /**
-   * Request one of the 8 interrupts asynchronously on this digital input.
-   *
-   * Request interrupts in asynchronous mode where the user's interrupt handler
-   * will be called when the interrupt fires. Users that want control over the
-   * thread priority should use the synchronous method with their own spawned
-   * thread. The default is interrupt on rising edges only.
-   */
-  virtual void RequestInterrupts(InterruptEventHandler handler);
-
-  /**
-   * 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 WaitForInterrupt.
-   * The default is interrupt on rising edges only.
-   */
-  virtual void RequestInterrupts();
-
-  /**
-   * Cancel interrupts on this device.
-   *
-   * This deallocates all the chipobject structures and disables any interrupts.
-   */
-  virtual void CancelInterrupts();
-
-  /**
-   * In synchronous mode, wait for the defined interrupt to occur.
-   *
-   * You should <b>NOT</b> attempt to read the sensor from another thread while
-   * waiting for an interrupt. This is not threadsafe, and can cause memory
-   * corruption
-   *
-   * @param timeout        Timeout in seconds
-   * @param ignorePrevious If true, ignore interrupts that happened before
-   *                       WaitForInterrupt was called.
-   * @return What interrupts fired
-   */
-  virtual WaitResult WaitForInterrupt(double timeout,
-                                      bool ignorePrevious = 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.
-   */
-  virtual void EnableInterrupts();
-
-  /**
-   * Disable Interrupts without without deallocating structures.
-   */
-  virtual void DisableInterrupts();
-
-  /**
-   * 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 SetUpSourceEdge().
-   *
-   * @return Timestamp in seconds since boot.
-   */
-  virtual double ReadRisingTimestamp();
-
-  /**
-   * 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 #DigitalInput.SetUpSourceEdge}
-   *
-   * @return Timestamp in seconds since boot.
-   */
-  virtual double ReadFallingTimestamp();
-
-  /**
-   * Set which edge to trigger interrupts on
-   *
-   * @param risingEdge  true to interrupt on rising edge
-   * @param fallingEdge true to interrupt on falling edge
-   */
-  virtual void SetUpSourceEdge(bool risingEdge, bool fallingEdge);
-
- protected:
-  hal::Handle<HAL_InterruptHandle> m_interrupt;
-  std::unique_ptr<InterruptEventHandler> m_interruptHandler{nullptr};
-
-  void AllocateInterrupts(bool watcher);
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/IterativeRobot.h b/wpilibc/src/main/native/include/frc/IterativeRobot.h
deleted file mode 100644
index 24fdba3..0000000
--- a/wpilibc/src/main/native/include/frc/IterativeRobot.h
+++ /dev/null
@@ -1,53 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <atomic>
-
-#include "frc/IterativeRobotBase.h"
-
-namespace frc {
-
-/**
- * IterativeRobot implements the IterativeRobotBase robot program framework.
- *
- * The IterativeRobot class is intended to be subclassed by a user creating a
- * robot program.
- *
- * 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.
- */
-class IterativeRobot : public IterativeRobotBase {
- public:
-  WPI_DEPRECATED(
-      "Use TimedRobot instead. It's a drop-in replacement that provides more "
-      "regular execution periods.")
-  IterativeRobot();
-  virtual ~IterativeRobot() = default;
-
-  /**
-   * Provide an alternate "main loop" via StartCompetition().
-   *
-   * This specific StartCompetition() implements "main loop" behavior synced
-   * with the DS packets.
-   */
-  void StartCompetition() override;
-
-  /**
-   * Ends the main loop in StartCompetition().
-   */
-  void EndCompetition() override;
-
- private:
-  std::atomic<bool> m_exit{false};
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/IterativeRobotBase.h b/wpilibc/src/main/native/include/frc/IterativeRobotBase.h
index 66897aa..c4253ef 100644
--- a/wpilibc/src/main/native/include/frc/IterativeRobotBase.h
+++ b/wpilibc/src/main/native/include/frc/IterativeRobotBase.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -28,22 +25,32 @@
  * RobotInit() -- provide for initialization at robot power-on
  *
  * 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
+ * appropriate mode is entered:
+ *
+ * \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
  *
  * Periodic() functions -- each of these functions is called on an interval:
- *   - RobotPeriodic()
- *   - DisabledPeriodic()
- *   - AutonomousPeriodic()
- *   - TeleopPeriodic()
- *   - TestPeriodic()
+ *
+ * \li RobotPeriodic()
+ * \li DisabledPeriodic()
+ * \li AutonomousPeriodic()
+ * \li TeleopPeriodic()
+ * \li TestPeriodic()
+ *
+ * Exit() functions -- each of the following functions is called once when the
+ * appropriate mode is exited:
+ *
+ * \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
  */
 class IterativeRobotBase : public RobotBase {
  public:
@@ -156,6 +163,51 @@
   virtual void TestPeriodic();
 
   /**
+   * Exit code for disabled mode should go here.
+   *
+   * Users should override this method for code which will be called each time
+   * the robot exits disabled mode.
+   */
+  virtual void DisabledExit();
+
+  /**
+   * Exit code for autonomous mode should go here.
+   *
+   * Users should override this method for code which will be called each time
+   * the robot exits autonomous mode.
+   */
+  virtual void AutonomousExit();
+
+  /**
+   * Exit code for teleop mode should go here.
+   *
+   * Users should override this method for code which will be called each time
+   * the robot exits teleop mode.
+   */
+  virtual void TeleopExit();
+
+  /**
+   * Exit code for test mode should go here.
+   *
+   * Users should override this method for code which will be called each time
+   * the robot exits test mode.
+   */
+  virtual void TestExit();
+
+  /**
+   * Enables or disables flushing NetworkTables every loop iteration.
+   * By default, this is disabled.
+   *
+   * @param enabled True to enable, false to disable
+   */
+  void SetNetworkTablesFlushEnabled(bool enabled);
+
+  /**
+   * Gets time period between calls to Periodic() functions.
+   */
+  units::second_t GetPeriod() const;
+
+  /**
    * Constructor for IterativeRobotBase.
    *
    * @param period Period in seconds.
@@ -173,7 +225,7 @@
    */
   explicit IterativeRobotBase(units::second_t period);
 
-  virtual ~IterativeRobotBase() = default;
+  ~IterativeRobotBase() override = default;
 
  protected:
   IterativeRobotBase(IterativeRobotBase&&) = default;
@@ -181,13 +233,13 @@
 
   void LoopFunc();
 
-  units::second_t m_period;
-
  private:
   enum class Mode { kNone, kDisabled, kAutonomous, kTeleop, kTest };
 
   Mode m_lastMode = Mode::kNone;
+  units::second_t m_period;
   Watchdog m_watchdog;
+  bool m_ntFlushEnabled = false;
 
   void PrintLoopOverrunMessage();
 };
diff --git a/wpilibc/src/main/native/include/frc/Joystick.h b/wpilibc/src/main/native/include/frc/Joystick.h
index 0975e6d..0d63e4e 100644
--- a/wpilibc/src/main/native/include/frc/Joystick.h
+++ b/wpilibc/src/main/native/include/frc/Joystick.h
@@ -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.
 
 #pragma once
 
@@ -42,7 +39,7 @@
    */
   explicit Joystick(int port);
 
-  virtual ~Joystick() = default;
+  ~Joystick() override = default;
 
   Joystick(Joystick&&) = default;
   Joystick& operator=(Joystick&&) = default;
@@ -57,7 +54,6 @@
   /**
    * Set the channel associated with the Y axis.
    *
-   * @param axis    The axis to set the channel for.
    * @param channel The channel to set the axis to.
    */
   void SetYChannel(int channel);
@@ -65,7 +61,6 @@
   /**
    * Set the channel associated with the Z axis.
    *
-   * @param axis    The axis to set the channel for.
    * @param channel The channel to set the axis to.
    */
   void SetZChannel(int channel);
@@ -73,7 +68,6 @@
   /**
    * Set the channel associated with the twist axis.
    *
-   * @param axis    The axis to set the channel for.
    * @param channel The channel to set the axis to.
    */
   void SetTwistChannel(int channel);
@@ -81,7 +75,6 @@
   /**
    * Set the channel associated with the throttle axis.
    *
-   * @param axis    The axis to set the channel for.
    * @param channel The channel to set the axis to.
    */
   void SetThrottleChannel(int channel);
@@ -122,24 +115,18 @@
   int GetThrottleChannel() const;
 
   /**
-   * Get the X value of the joystick.
+   * Get the X value of the current joystick.
    *
    * This depends on the mapping of the joystick connected to the current port.
-   *
-   * @param hand This parameter is ignored for the Joystick class and is only
-   *             here to complete the GenericHID interface.
    */
-  double GetX(JoystickHand hand = kRightHand) const override;
+  double GetX() const;
 
   /**
-   * Get the Y value of the joystick.
+   * Get the Y value of the current joystick.
    *
    * This depends on the mapping of the joystick connected to the current port.
-   *
-   * @param hand This parameter is ignored for the Joystick class and is only
-   *             here to complete the GenericHID interface.
    */
-  double GetY(JoystickHand hand = kRightHand) const override;
+  double GetY() const;
 
   /**
    * Get the Z value of the current joystick.
diff --git a/wpilibc/src/main/native/include/frc/MotorSafety.h b/wpilibc/src/main/native/include/frc/MotorSafety.h
index afd0853..f84af17 100644
--- a/wpilibc/src/main/native/include/frc/MotorSafety.h
+++ b/wpilibc/src/main/native/include/frc/MotorSafety.h
@@ -1,16 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/mutex.h>
-#include <wpi/raw_ostream.h>
+#include <string>
 
-#include "frc/ErrorBase.h"
+#include <units/time.h>
+#include <wpi/mutex.h>
+
 #include "frc/Timer.h"
 
 namespace frc {
@@ -21,7 +19,7 @@
  *
  * The subclass should call Feed() whenever the motor value is updated.
  */
-class MotorSafety : public ErrorBase {
+class MotorSafety {
  public:
   MotorSafety();
   virtual ~MotorSafety();
@@ -39,16 +37,16 @@
   /**
    * Set the expiration time for the corresponding motor safety object.
    *
-   * @param expirationTime The timeout value in seconds.
+   * @param expirationTime The timeout value.
    */
-  void SetExpiration(double expirationTime);
+  void SetExpiration(units::second_t expirationTime);
 
   /**
    * Retrieve the timeout value for the corresponding motor safety object.
    *
-   * @return the timeout value in seconds.
+   * @return the timeout value.
    */
-  double GetExpiration() const;
+  units::second_t GetExpiration() const;
 
   /**
    * Determine if the motor is still operating or has timed out.
@@ -93,19 +91,19 @@
   static void CheckMotors();
 
   virtual void StopMotor() = 0;
-  virtual void GetDescription(wpi::raw_ostream& desc) const = 0;
+  virtual std::string GetDescription() const = 0;
 
  private:
-  static constexpr double kDefaultSafetyExpiration = 0.1;
+  static constexpr auto kDefaultSafetyExpiration = 100_ms;
 
   // The expiration time for this object
-  double m_expiration = kDefaultSafetyExpiration;
+  units::second_t m_expiration = kDefaultSafetyExpiration;
 
   // True if motor safety is enabled for this motor
   bool m_enabled = false;
 
   // The FPGA clock value when the motor has expired
-  double m_stopTime = Timer::GetFPGATimestamp();
+  units::second_t m_stopTime = Timer::GetFPGATimestamp();
 
   mutable wpi::mutex m_thisMutex;
 };
diff --git a/wpilibc/src/main/native/include/frc/Notifier.h b/wpilibc/src/main/native/include/frc/Notifier.h
index c9348a6..61b7fbb 100644
--- a/wpilibc/src/main/native/include/frc/Notifier.h
+++ b/wpilibc/src/main/native/include/frc/Notifier.h
@@ -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.
 
 #pragma once
 
@@ -11,21 +8,18 @@
 
 #include <atomic>
 #include <functional>
+#include <string_view>
 #include <thread>
 #include <type_traits>
 #include <utility>
 
 #include <hal/Types.h>
 #include <units/time.h>
-#include <wpi/Twine.h>
-#include <wpi/deprecated.h>
 #include <wpi/mutex.h>
 
-#include "frc/ErrorBase.h"
-
 namespace frc {
 
-class Notifier : public ErrorBase {
+class Notifier {
  public:
   /**
    * Create a Notifier for timer event notification.
@@ -49,8 +43,9 @@
    * This is useful for reducing scheduling jitter on processes which are
    * sensitive to timing variance, like model-based control.
    *
-   * @param priority The FIFO real-time scheduler priority ([0..100] where a
-   *                 lower number represents higher priority).
+   * @param priority The FIFO real-time scheduler priority ([1..99] where a
+   *                 higher number represents higher priority). See "man 7
+   *                 sched" for more details.
    * @param handler  The handler is called at the notification time which is set
    *                 using StartSingle or StartPeriodic.
    */
@@ -65,7 +60,7 @@
   /**
    * Free the resources for a timer event.
    */
-  virtual ~Notifier();
+  ~Notifier();
 
   Notifier(Notifier&& rhs);
   Notifier& operator=(Notifier&& rhs);
@@ -75,7 +70,7 @@
    *
    * @param name Name
    */
-  void SetName(const wpi::Twine& name);
+  void SetName(std::string_view name);
 
   /**
    * Change the handler function.
@@ -89,19 +84,6 @@
    *
    * A timer event is queued for a single event after the specified delay.
    *
-   * @deprecated Use unit-safe StartSingle(units::second_t delay) method
-   * instead.
-   *
-   * @param delay Seconds to wait before the handler is called.
-   */
-  WPI_DEPRECATED("Use unit-safe StartSingle method instead.")
-  void StartSingle(double delay);
-
-  /**
-   * Register for single event notification.
-   *
-   * A timer event is queued for a single event after the specified delay.
-   *
    * @param delay Amount of time to wait before the handler is called.
    */
   void StartSingle(units::second_t delay);
@@ -113,22 +95,6 @@
    * interrupt occurs, the event will be immediately requeued for the same time
    * interval.
    *
-   * @deprecated Use unit-safe StartPeriodic(units::second_t period) method
-   * instead
-   *
-   * @param period Period in seconds to call the handler starting one period
-   *               after the call to this method.
-   */
-  WPI_DEPRECATED("Use unit-safe StartPeriodic method instead.")
-  void StartPeriodic(double period);
-
-  /**
-   * 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 to call the handler starting one period
    *               after the call to this method.
    */
@@ -145,6 +111,23 @@
    */
   void Stop();
 
+  /**
+   * Sets the HAL notifier thread priority.
+   *
+   * 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.
+   */
+  static bool SetHALThreadPriority(bool realTime, int32_t priority);
+
  private:
   /**
    * Update the HAL alarm time.
@@ -171,10 +154,10 @@
   std::function<void()> m_handler;
 
   // The absolute expiration time
-  double m_expirationTime = 0;
+  units::second_t m_expirationTime = 0_s;
 
   // The relative time (either periodic or single)
-  double m_period = 0;
+  units::second_t m_period = 0_s;
 
   // True if this is a periodic event
   bool m_periodic = false;
diff --git a/wpilibc/src/main/native/include/frc/PIDBase.h b/wpilibc/src/main/native/include/frc/PIDBase.h
deleted file mode 100644
index 79d8eba..0000000
--- a/wpilibc/src/main/native/include/frc/PIDBase.h
+++ /dev/null
@@ -1,410 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include <wpi/deprecated.h>
-#include <wpi/mutex.h>
-
-#include "frc/Base.h"
-#include "frc/LinearFilter.h"
-#include "frc/PIDInterface.h"
-#include "frc/PIDOutput.h"
-#include "frc/PIDSource.h"
-#include "frc/Timer.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
-
-namespace frc {
-
-class SendableBuilder;
-
-/**
- * Class implements a PID Control Loop.
- *
- * Creates a separate thread which reads the given PIDSource and takes care of
- * the integral calculations, as well as writing the given PIDOutput.
- *
- * 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.
- */
-class PIDBase : public PIDInterface,
-                public PIDOutput,
-                public Sendable,
-                public SendableHelper<PIDBase> {
- public:
-  /**
-   * Allocate a PID object with the given constants for P, I, 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 value
-   */
-  WPI_DEPRECATED("All APIs which use this have been deprecated.")
-  PIDBase(double p, double i, double d, PIDSource& source, PIDOutput& output);
-
-  /**
-   * Allocate a PID object with the given constants for P, I, 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 value
-   */
-  WPI_DEPRECATED("All APIs which use this have been deprecated.")
-  PIDBase(double p, double i, double d, double f, PIDSource& source,
-          PIDOutput& output);
-
-  virtual ~PIDBase() = default;
-
-  /**
-   * Return the current PID result.
-   *
-   * This is always centered on zero and constrained the the max and min outs.
-   *
-   * @return the latest calculated output
-   */
-  virtual double Get() const;
-
-  /**
-   * 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 true turns on continuous, false turns off continuous
-   */
-  virtual void SetContinuous(bool continuous = true);
-
-  /**
-   * Sets the maximum and minimum values expected from the input.
-   *
-   * @param minimumInput the minimum value expected from the input
-   * @param maximumInput the maximum value expected from the output
-   */
-  virtual void SetInputRange(double minimumInput, double maximumInput);
-
-  /**
-   * Sets the minimum and maximum values to write.
-   *
-   * @param minimumOutput the minimum value to write to the output
-   * @param maximumOutput the maximum value to write to the output
-   */
-  virtual void SetOutputRange(double minimumOutput, double maximumOutput);
-
-  /**
-   * 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
-   */
-  void SetPID(double p, double i, double d) override;
-
-  /**
-   * 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
-   */
-  virtual void SetPID(double p, double i, double d, double f);
-
-  /**
-   * Set the Proportional coefficient of the PID controller gain.
-   *
-   * @param p proportional coefficient
-   */
-  void SetP(double p);
-
-  /**
-   * Set the Integral coefficient of the PID controller gain.
-   *
-   * @param i integral coefficient
-   */
-  void SetI(double i);
-
-  /**
-   * Set the Differential coefficient of the PID controller gain.
-   *
-   * @param d differential coefficient
-   */
-  void SetD(double d);
-
-  /**
-   * Get the Feed forward coefficient of the PID controller gain.
-   *
-   * @param f Feed forward coefficient
-   */
-  void SetF(double f);
-
-  /**
-   * Get the Proportional coefficient.
-   *
-   * @return proportional coefficient
-   */
-  double GetP() const override;
-
-  /**
-   * Get the Integral coefficient.
-   *
-   * @return integral coefficient
-   */
-  double GetI() const override;
-
-  /**
-   * Get the Differential coefficient.
-   *
-   * @return differential coefficient
-   */
-  double GetD() const override;
-
-  /**
-   * Get the Feed forward coefficient.
-   *
-   * @return Feed forward coefficient
-   */
-  virtual double GetF() const;
-
-  /**
-   * Set the setpoint for the PIDBase.
-   *
-   * @param setpoint the desired setpoint
-   */
-  void SetSetpoint(double setpoint) override;
-
-  /**
-   * Returns the current setpoint of the PIDBase.
-   *
-   * @return the current setpoint
-   */
-  double GetSetpoint() const override;
-
-  /**
-   * Returns the change in setpoint over time of the PIDBase.
-   *
-   * @return the change in setpoint over time
-   */
-  double GetDeltaSetpoint() const;
-
-  /**
-   * Returns the current difference of the input from the setpoint.
-   *
-   * @return the current error
-   */
-  virtual double GetError() const;
-
-  /**
-   * Returns the current average of the error over the past few iterations.
-   *
-   * You can specify the number of iterations to average with
-   * SetToleranceBuffer() (defaults to 1). This is the same value that is used
-   * for OnTarget().
-   *
-   * @return the average error
-   */
-  WPI_DEPRECATED("Use a LinearFilter as the input and GetError().")
-  virtual double GetAvgError() const;
-
-  /**
-   * Sets what type of input the PID controller will use.
-   */
-  virtual void SetPIDSourceType(PIDSourceType pidSource);
-
-  /**
-   * Returns the type of input the PID controller is using.
-   *
-   * @return the PID controller input type
-   */
-  virtual PIDSourceType GetPIDSourceType() const;
-
-  /**
-   * Set the percentage error which is considered tolerable for use with
-   * OnTarget.
-   *
-   * @param percentage error which is tolerable
-   */
-  WPI_DEPRECATED("Use SetPercentTolerance() instead.")
-  virtual void SetTolerance(double percent);
-
-  /**
-   * Set the absolute error which is considered tolerable for use with
-   * OnTarget.
-   *
-   * @param percentage error which is tolerable
-   */
-  virtual void SetAbsoluteTolerance(double absValue);
-
-  /**
-   * Set the percentage error which is considered tolerable for use with
-   * OnTarget.
-   *
-   * @param percentage error which is tolerable
-   */
-  virtual void SetPercentTolerance(double percentValue);
-
-  /**
-   * 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.
-   *
-   * @param bufLength Number of previous cycles to average. Defaults to 1.
-   */
-  WPI_DEPRECATED("Use a LinearDigitalFilter as the input.")
-  virtual void SetToleranceBuffer(int buf = 1);
-
-  /**
-   * Return true if the error is within the percentage of the total input range,
-   * determined by SetTolerance. This asssumes that the maximum and minimum
-   * input were set using SetInput.
-   *
-   * Currently this just reports on target as the actual value passes through
-   * the setpoint. Ideally it should be based on being within the tolerance for
-   * some period of time.
-   *
-   * This will return false until at least one input value has been computed.
-   */
-  virtual bool OnTarget() const;
-
-  /**
-   * Reset the previous error, the integral term, and disable the controller.
-   */
-  void Reset() override;
-
-  /**
-   * Passes the output directly to SetSetpoint().
-   *
-   * 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.
-   *
-   * It is the caller's responsibility to put the data into a valid form for
-   * SetSetpoint().
-   */
-  void PIDWrite(double output) override;
-
-  void InitSendable(SendableBuilder& builder) override;
-
- protected:
-  // Is the pid controller enabled
-  bool m_enabled = false;
-
-  mutable wpi::mutex m_thisMutex;
-
-  // Ensures when Disable() is called, PIDWrite() won't run if Calculate()
-  // is already running at that time.
-  mutable wpi::mutex m_pidWriteMutex;
-
-  PIDSource* m_pidInput;
-  PIDOutput* m_pidOutput;
-  Timer m_setpointTimer;
-
-  /**
-   * Read the input, calculate the output accordingly, and write to the output.
-   * This should only be called by the Notifier.
-   */
-  virtual void Calculate();
-
-  /**
-   * Calculate the feed forward term.
-   *
-   * 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 PIDBase class only calls it in synchronized
-   * code, so be careful if calling it oneself.
-   *
-   * 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).
-   */
-  virtual double CalculateFeedForward();
-
-  /**
-   * 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.
-   */
-  double GetContinuousError(double error) const;
-
- private:
-  // Factor for "proportional" control
-  double m_P;
-
-  // Factor for "integral" control
-  double m_I;
-
-  // Factor for "derivative" control
-  double m_D;
-
-  // Factor for "feed forward" control
-  double m_F;
-
-  // |maximum output|
-  double m_maximumOutput = 1.0;
-
-  // |minimum output|
-  double m_minimumOutput = -1.0;
-
-  // Maximum input - limit setpoint to this
-  double m_maximumInput = 0;
-
-  // Minimum input - limit setpoint to this
-  double m_minimumInput = 0;
-
-  // input range - difference between maximum and minimum
-  double m_inputRange = 0;
-
-  // Do the endpoints wrap around? eg. Absolute encoder
-  bool m_continuous = false;
-
-  // The prior error (used to compute velocity)
-  double m_prevError = 0;
-
-  // The sum of the errors for use in the integral calc
-  double m_totalError = 0;
-
-  enum {
-    kAbsoluteTolerance,
-    kPercentTolerance,
-    kNoTolerance
-  } m_toleranceType = kNoTolerance;
-
-  // The percetage or absolute error that is considered on target.
-  double m_tolerance = 0.05;
-
-  double m_setpoint = 0;
-  double m_prevSetpoint = 0;
-  double m_error = 0;
-  double m_result = 0;
-
-  LinearFilter<double> m_filter{{}, {}};
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PIDController.h b/wpilibc/src/main/native/include/frc/PIDController.h
deleted file mode 100644
index 39e4deb..0000000
--- a/wpilibc/src/main/native/include/frc/PIDController.h
+++ /dev/null
@@ -1,139 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include <wpi/deprecated.h>
-#include <wpi/mutex.h>
-
-#include "frc/Base.h"
-#include "frc/Controller.h"
-#include "frc/Notifier.h"
-#include "frc/PIDBase.h"
-#include "frc/PIDSource.h"
-#include "frc/Timer.h"
-
-namespace frc {
-
-class PIDOutput;
-
-/**
- * Class implements a PID Control Loop.
- *
- * Creates a separate thread which reads the given PIDSource and takes care of
- * the integral calculations, as well as writing the given PIDOutput.
- *
- * 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 frc2::PIDController class instead.
- */
-class PIDController : public PIDBase, public Controller {
- public:
-  /**
-   * Allocate a PID object with the given constants for P, I, 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 value
-   * @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).
-   */
-  WPI_DEPRECATED("Use frc2::PIDController class instead.")
-  PIDController(double p, double i, double d, PIDSource* source,
-                PIDOutput* output, double period = 0.05);
-
-  /**
-   * Allocate a PID object with the given constants for P, I, 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 value
-   * @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).
-   */
-  WPI_DEPRECATED("Use frc2::PIDController class instead.")
-  PIDController(double p, double i, double d, double f, PIDSource* source,
-                PIDOutput* output, double period = 0.05);
-
-  /**
-   * Allocate a PID object with the given constants for P, I, 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 value
-   * @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).
-   */
-  WPI_DEPRECATED("Use frc2::PIDController class instead.")
-  PIDController(double p, double i, double d, PIDSource& source,
-                PIDOutput& output, double period = 0.05);
-
-  /**
-   * Allocate a PID object with the given constants for P, I, 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 value
-   * @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).
-   */
-  WPI_DEPRECATED("Use frc2::PIDController class instead.")
-  PIDController(double p, double i, double d, double f, PIDSource& source,
-                PIDOutput& output, double period = 0.05);
-
-  ~PIDController() override;
-
-  /**
-   * Begin running the PIDController.
-   */
-  void Enable() override;
-
-  /**
-   * Stop running the PIDController, this sets the output to zero before
-   * stopping.
-   */
-  void Disable() override;
-
-  /**
-   * Set the enabled state of the PIDController.
-   */
-  void SetEnabled(bool enable);
-
-  /**
-   * Return true if PIDController is enabled.
-   */
-  bool IsEnabled() const;
-
-  /**
-   * Reset the previous error, the integral term, and disable the controller.
-   */
-  void Reset() override;
-
-  void InitSendable(SendableBuilder& builder) override;
-
- private:
-  std::unique_ptr<Notifier> m_controlLoop;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PIDInterface.h b/wpilibc/src/main/native/include/frc/PIDInterface.h
deleted file mode 100644
index 8d847a6..0000000
--- a/wpilibc/src/main/native/include/frc/PIDInterface.h
+++ /dev/null
@@ -1,37 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <wpi/deprecated.h>
-
-namespace frc {
-
-/**
- * Interface for PID Control Loop.
- *
- * @deprecated All APIs which use this have been deprecated.
- */
-class PIDInterface {
- public:
-  WPI_DEPRECATED("All APIs which use this have been deprecated.")
-  PIDInterface() = default;
-  PIDInterface(PIDInterface&&) = default;
-  PIDInterface& operator=(PIDInterface&&) = default;
-
-  virtual void SetPID(double p, double i, double d) = 0;
-  virtual double GetP() const = 0;
-  virtual double GetI() const = 0;
-  virtual double GetD() const = 0;
-
-  virtual void SetSetpoint(double setpoint) = 0;
-  virtual double GetSetpoint() const = 0;
-
-  virtual void Reset() = 0;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PIDOutput.h b/wpilibc/src/main/native/include/frc/PIDOutput.h
deleted file mode 100644
index 37fb2a1..0000000
--- a/wpilibc/src/main/native/include/frc/PIDOutput.h
+++ /dev/null
@@ -1,25 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/Base.h"
-
-namespace frc {
-
-/**
- * PIDOutput interface is a generic output for the PID class.
- *
- * PWMs use this class. Users implement this interface to allow for a
- * PIDController to read directly from the inputs.
- */
-class PIDOutput {
- public:
-  virtual void PIDWrite(double output) = 0;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PIDSource.h b/wpilibc/src/main/native/include/frc/PIDSource.h
deleted file mode 100644
index 1a807b1..0000000
--- a/wpilibc/src/main/native/include/frc/PIDSource.h
+++ /dev/null
@@ -1,39 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-namespace frc {
-
-enum class PIDSourceType { kDisplacement, kRate };
-
-/**
- * PIDSource interface is a generic sensor source for the PID class.
- *
- * All sensors that can be used with the PID class will implement the PIDSource
- * that returns a standard value that will be used in the PID code.
- */
-class PIDSource {
- public:
-  virtual ~PIDSource() = default;
-
-  /**
-   * Set which parameter you are using as a process control variable.
-   *
-   * @param pidSource An enum to select the parameter.
-   */
-  virtual void SetPIDSourceType(PIDSourceType pidSource);
-
-  virtual PIDSourceType GetPIDSourceType() const;
-
-  virtual double PIDGet() = 0;
-
- protected:
-  PIDSourceType m_pidSource = PIDSourceType::kDisplacement;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PS4Controller.h b/wpilibc/src/main/native/include/frc/PS4Controller.h
new file mode 100644
index 0000000..ee87501
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/PS4Controller.h
@@ -0,0 +1,403 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include "frc/GenericHID.h"
+
+namespace frc {
+
+/**
+ * Handle input from 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.
+ */
+class PS4Controller : public GenericHID {
+ public:
+  /**
+   * Construct an instance of an PS4 controller.
+   *
+   * The controller index is the USB port on the Driver Station.
+   *
+   * @param port The port on the Driver Station that the controller is plugged
+   *             into (0-5).
+   */
+  explicit PS4Controller(int port);
+
+  ~PS4Controller() override = default;
+
+  PS4Controller(PS4Controller&&) = default;
+  PS4Controller& operator=(PS4Controller&&) = default;
+
+  /**
+   * Get the X axis value of left side of the controller.
+   *
+   * @return the axis value.
+   */
+  double GetLeftX() const;
+
+  /**
+   * Get the X axis value of right side of the controller.
+   *
+   * @return the axis value.
+   */
+  double GetRightX() const;
+
+  /**
+   * Get the Y axis value of left side of the controller.
+   *
+   * @return the axis value.
+   */
+  double GetLeftY() const;
+
+  /**
+   * Get the Y axis value of right side of the controller.
+   *
+   * @return the axis value.
+   */
+  double GetRightY() const;
+
+  /**
+   * Get the L2 axis value of the controller. Note that this axis is bound to
+   * the range of [0, 1] as opposed to the usual [-1, 1].
+   *
+   * @return the axis value.
+   */
+  double GetL2Axis() const;
+
+  /**
+   * Get the R2 axis value of the controller. Note that this axis is bound to
+   * the range of [0, 1] as opposed to the usual [-1, 1].
+   *
+   * @return the axis value.
+   */
+  double GetR2Axis() const;
+
+  /**
+   * Read the value of the Square button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetSquareButton() const;
+
+  /**
+   * Whether the Square button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetSquareButtonPressed();
+
+  /**
+   * Whether the Square button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetSquareButtonReleased();
+
+  /**
+   * Read the value of the Cross button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetCrossButton() const;
+
+  /**
+   * Whether the Cross button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetCrossButtonPressed();
+
+  /**
+   * Whether the Cross button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetCrossButtonReleased();
+
+  /**
+   * Read the value of the Circle button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetCircleButton() const;
+
+  /**
+   * Whether the Circle button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetCircleButtonPressed();
+
+  /**
+   * Whether the Circle button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetCircleButtonReleased();
+
+  /**
+   * Read the value of the Triangle button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetTriangleButton() const;
+
+  /**
+   * Whether the Triangle button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetTriangleButtonPressed();
+
+  /**
+   * Whether the Triangle button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetTriangleButtonReleased();
+
+  /**
+   * Read the value of the L1 button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetL1Button() const;
+
+  /**
+   * Whether the L1 button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetL1ButtonPressed();
+
+  /**
+   * Whether the L1 button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetL1ButtonReleased();
+
+  /**
+   * Read the value of the R1 button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetR1Button() const;
+
+  /**
+   * Whether the R1 button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetR1ButtonPressed();
+
+  /**
+   * Whether the R1 button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetR1ButtonReleased();
+
+  /**
+   * Read the value of the L2 button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetL2Button() const;
+
+  /**
+   * Whether the L2 button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetL2ButtonPressed();
+
+  /**
+   * Whether the L2 button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetL2ButtonReleased();
+
+  /**
+   * Read the value of the R2 button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetR2Button() const;
+
+  /**
+   * Whether the R2 button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetR2ButtonPressed();
+
+  /**
+   * Whether the R2 button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetR2ButtonReleased();
+
+  /**
+   * Read the value of the Share button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetShareButton() const;
+
+  /**
+   * Whether the Share button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetShareButtonPressed();
+
+  /**
+   * Whether the Share button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetShareButtonReleased();
+
+  /**
+   * Read the value of the Options button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetOptionsButton() const;
+
+  /**
+   * Whether the Options button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetOptionsButtonPressed();
+
+  /**
+   * Whether the Options button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetOptionsButtonReleased();
+
+  /**
+   * Read the value of the L3 button (pressing the left analog stick) on the
+   * controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetL3Button() const;
+
+  /**
+   * Whether the L3 (left stick) button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetL3ButtonPressed();
+
+  /**
+   * Whether the L3 (left stick) button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetL3ButtonReleased();
+
+  /**
+   * Read the value of the R3 button (pressing the right analog stick) on the
+   * controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetR3Button() const;
+
+  /**
+   * Whether the R3 (right stick) button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetR3ButtonPressed();
+
+  /**
+   * Whether the R3 (right stick) button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetR3ButtonReleased();
+
+  /**
+   * Read the value of the PS button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetPSButton() const;
+
+  /**
+   * Whether the PS button was pressed since the last check.
+   *
+   * @return Whether the button was pressed since the last check.
+   */
+  bool GetPSButtonPressed();
+
+  /**
+   * Whether the PS button was released since the last check.
+   *
+   * @return Whether the button was released since the last check.
+   */
+  bool GetPSButtonReleased();
+
+  /**
+   * Read the value of the touchpad button on the controller.
+   *
+   * @return The state of the button.
+   */
+  bool GetTouchpad() const;
+
+  /**
+   * Whether the touchpad was pressed since the last check.
+   *
+   * @return Whether the touchpad was pressed since the last check.
+   */
+  bool GetTouchpadPressed();
+
+  /**
+   * Whether the touchpad was released since the last check.
+   *
+   * @return Whether the touchpad was released since the last check.
+   */
+  bool GetTouchpadReleased();
+
+  struct Button {
+    static constexpr int kSquare = 1;
+    static constexpr int kCross = 2;
+    static constexpr int kCircle = 3;
+    static constexpr int kTriangle = 4;
+    static constexpr int kL1 = 5;
+    static constexpr int kR1 = 6;
+    static constexpr int kL2 = 7;
+    static constexpr int kR2 = 8;
+    static constexpr int kShare = 9;
+    static constexpr int kOptions = 10;
+    static constexpr int kL3 = 11;
+    static constexpr int kR3 = 12;
+    static constexpr int kPS = 13;
+    static constexpr int kTouchpad = 14;
+  };
+
+  struct Axis {
+    static constexpr int kLeftX = 0;
+    static constexpr int kLeftY = 1;
+    static constexpr int kRightX = 2;
+    static constexpr int kRightY = 5;
+    static constexpr int kL2 = 3;
+    static constexpr int kR2 = 4;
+  };
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PWM.h b/wpilibc/src/main/native/include/frc/PWM.h
index 406a93e..efff540 100644
--- a/wpilibc/src/main/native/include/frc/PWM.h
+++ b/wpilibc/src/main/native/include/frc/PWM.h
@@ -1,24 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <stdint.h>
 
 #include <hal/Types.h>
-#include <wpi/raw_ostream.h>
-
-#include "frc/MotorSafety.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 namespace frc {
 class AddressableLED;
-class SendableBuilder;
+class DMA;
 
 /**
  * Class implements the PWM generation in the FPGA.
@@ -37,9 +31,10 @@
  *   - 1 = minimum pulse width (currently 0.5ms)
  *   - 0 = disabled (i.e. PWM output is held low)
  */
-class PWM : public MotorSafety, public Sendable, public SendableHelper<PWM> {
+class PWM : public wpi::Sendable, public wpi::SendableHelper<PWM> {
  public:
   friend class AddressableLED;
+  friend class DMA;
   /**
    * Represents the amount to multiply the minimum servo-pulse pwm period by.
    */
@@ -67,8 +62,10 @@
    *
    * @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
    */
-  explicit PWM(int channel);
+  explicit PWM(int channel, bool registerSendable = true);
 
   /**
    * Free the PWM channel.
@@ -80,10 +77,6 @@
   PWM(PWM&&) = default;
   PWM& operator=(PWM&&) = default;
 
-  // MotorSafety interface
-  void StopMotor() override;
-  void GetDescription(wpi::raw_ostream& desc) const override;
-
   /**
    * Set the PWM value directly to the hardware.
    *
@@ -129,7 +122,7 @@
   /**
    * Set the PWM value based on a speed.
    *
-   * This is intended to be used by speed controllers.
+   * This is intended to be used by motor controllers.
    *
    * @pre SetMaxPositivePwm() called.
    * @pre SetMinPositivePwm() called.
@@ -137,14 +130,14 @@
    * @pre SetMaxNegativePwm() called.
    * @pre SetMinNegativePwm() called.
    *
-   * @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.
    */
   virtual void SetSpeed(double speed);
 
   /**
    * Get the PWM value in terms of speed.
    *
-   * This is intended to be used by speed controllers.
+   * This is intended to be used by motor controllers.
    *
    * @pre SetMaxPositivePwm() called.
    * @pre SetMinPositivePwm() called.
@@ -171,12 +164,12 @@
   void SetZeroLatch();
 
   /**
-   * 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 on the speed
+   *                          controller to eliminate the deadband in the middle
+   *                          of the range. Otherwise, keep the full range
+   *                          without modifying any values.
    */
   void EnableDeadbandElimination(bool eliminateDeadband);
 
@@ -231,7 +224,7 @@
   int GetChannel() const;
 
  protected:
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   int m_channel;
diff --git a/wpilibc/src/main/native/include/frc/PWMSpeedController.h b/wpilibc/src/main/native/include/frc/PWMSpeedController.h
deleted file mode 100644
index b827d30..0000000
--- a/wpilibc/src/main/native/include/frc/PWMSpeedController.h
+++ /dev/null
@@ -1,70 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/PWM.h"
-#include "frc/SpeedController.h"
-
-namespace frc {
-
-/**
- * Common base class for all PWM Speed Controllers.
- */
-class PWMSpeedController : public PWM, public SpeedController {
- public:
-  PWMSpeedController(PWMSpeedController&&) = default;
-  PWMSpeedController& operator=(PWMSpeedController&&) = default;
-
-  /**
-   * Set the PWM value.
-   *
-   * 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.
-   */
-  void Set(double value) override;
-
-  /**
-   * Get the recently set value of the PWM.
-   *
-   * @return The most recently set value for the PWM between -1.0 and 1.0.
-   */
-  double Get() const override;
-
-  void SetInverted(bool isInverted) override;
-
-  bool GetInverted() const override;
-
-  void Disable() override;
-
-  void StopMotor() override;
-
-  /**
-   * 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
-   */
-  void PIDWrite(double output) override;
-
- protected:
-  /**
-   * Constructor for a PWM Speed Controller connected via PWM.
-   *
-   * @param channel The PWM channel that the controller is attached to. 0-9 are
-   *                on-board, 10-19 are on the MXP port
-   */
-  explicit PWMSpeedController(int channel);
-
-  void InitSendable(SendableBuilder& builder) override;
-
- private:
-  bool m_isInverted = false;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PWMTalonFX.h b/wpilibc/src/main/native/include/frc/PWMTalonFX.h
deleted file mode 100644
index d85c7ca..0000000
--- a/wpilibc/src/main/native/include/frc/PWMTalonFX.h
+++ /dev/null
@@ -1,45 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/PWMSpeedController.h"
-
-namespace frc {
-
-/**
- * Cross the Road Electronics (CTRE) Talon FX Speed Controller with PWM
- * control.
- *
- * Note that the Talon FX 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 FX User
- * Manual available from Cross The Road Electronics.
- *
- * \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"
- */
-class PWMTalonFX : public PWMSpeedController {
- public:
-  /**
-   * Construct a Talon FX 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
-   */
-  explicit PWMTalonFX(int channel);
-
-  PWMTalonFX(PWMTalonFX&&) = default;
-  PWMTalonFX& operator=(PWMTalonFX&&) = default;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PWMTalonSRX.h b/wpilibc/src/main/native/include/frc/PWMTalonSRX.h
deleted file mode 100644
index b9c8369..0000000
--- a/wpilibc/src/main/native/include/frc/PWMTalonSRX.h
+++ /dev/null
@@ -1,45 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/PWMSpeedController.h"
-
-namespace frc {
-
-/**
- * Cross the Road Electronics (CTRE) Talon SRX Speed Controller with PWM
- * control.
- *
- * Note that the Talon SRX 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 SRX User
- * Manual available from Cross The Road Electronics.
- *
- * \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"
- */
-class PWMTalonSRX : public PWMSpeedController {
- public:
-  /**
-   * Construct a Talon SRX 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
-   */
-  explicit PWMTalonSRX(int channel);
-
-  PWMTalonSRX(PWMTalonSRX&&) = default;
-  PWMTalonSRX& operator=(PWMTalonSRX&&) = default;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PWMVictorSPX.h b/wpilibc/src/main/native/include/frc/PWMVictorSPX.h
deleted file mode 100644
index a19e704..0000000
--- a/wpilibc/src/main/native/include/frc/PWMVictorSPX.h
+++ /dev/null
@@ -1,45 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/PWMSpeedController.h"
-
-namespace frc {
-
-/**
- * Cross the Road Electronics (CTRE) Victor SPX Speed Controller with PWM
- * control.
- *
- * 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 Cross The Road Electronics.
- *
- * \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"
- */
-class PWMVictorSPX : public PWMSpeedController {
- public:
-  /**
-   * Construct a Victor SPX connected via PWM.
-   *
-   * @param channel The PWM channel that the Victor SPX is attached to. 0-9
-   *                are on-board, 10-19 are on the MXP port
-   */
-  explicit PWMVictorSPX(int channel);
-
-  PWMVictorSPX(PWMVictorSPX&&) = default;
-  PWMVictorSPX& operator=(PWMVictorSPX&&) = default;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PneumaticHub.h b/wpilibc/src/main/native/include/frc/PneumaticHub.h
new file mode 100644
index 0000000..857ed51
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/PneumaticHub.h
@@ -0,0 +1,77 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <memory>
+
+#include <hal/Types.h>
+#include <wpi/DenseMap.h>
+#include <wpi/mutex.h>
+
+#include "PneumaticsBase.h"
+
+namespace frc {
+class PneumaticHub : public PneumaticsBase {
+ public:
+  PneumaticHub();
+  explicit PneumaticHub(int module);
+
+  ~PneumaticHub() override = default;
+
+  bool GetCompressor() const override;
+
+  void SetClosedLoopControl(bool enabled) override;
+
+  bool GetClosedLoopControl() const override;
+
+  bool GetPressureSwitch() const override;
+
+  double GetCompressorCurrent() const override;
+
+  void SetSolenoids(int mask, int values) override;
+
+  int GetSolenoids() const override;
+
+  int GetModuleNumber() const override;
+
+  int GetSolenoidDisabledList() const override;
+
+  void FireOneShot(int index) override;
+
+  void SetOneShotDuration(int index, units::second_t duration) override;
+
+  bool CheckSolenoidChannel(int channel) const override;
+
+  int CheckAndReserveSolenoids(int mask) override;
+
+  void UnreserveSolenoids(int mask) override;
+
+  bool ReserveCompressor() override;
+
+  void UnreserveCompressor() override;
+
+  Solenoid MakeSolenoid(int channel) override;
+  DoubleSolenoid MakeDoubleSolenoid(int forwardChannel,
+                                    int reverseChannel) override;
+  Compressor MakeCompressor() override;
+
+ private:
+  class DataStore;
+  friend class DataStore;
+  friend class PneumaticsBase;
+  PneumaticHub(HAL_REVPHHandle handle, int module);
+
+  static std::shared_ptr<PneumaticsBase> GetForModule(int module);
+
+  std::shared_ptr<DataStore> m_dataStore;
+  HAL_REVPHHandle m_handle;
+  int m_module;
+
+  static wpi::mutex m_handleLock;
+  static std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<DataStore>>>
+      m_handleMap;
+  static std::weak_ptr<DataStore>& GetDataStore(int module);
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PneumaticsBase.h b/wpilibc/src/main/native/include/frc/PneumaticsBase.h
new file mode 100644
index 0000000..06cad5d
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/PneumaticsBase.h
@@ -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.
+
+#pragma once
+
+#include <memory>
+
+#include <units/time.h>
+
+#include "frc/PneumaticsModuleType.h"
+
+namespace frc {
+class Solenoid;
+class DoubleSolenoid;
+class Compressor;
+class PneumaticsBase {
+ public:
+  virtual ~PneumaticsBase() = default;
+
+  virtual bool GetCompressor() const = 0;
+
+  virtual bool GetPressureSwitch() const = 0;
+
+  virtual double GetCompressorCurrent() const = 0;
+
+  virtual void SetClosedLoopControl(bool on) = 0;
+
+  virtual bool GetClosedLoopControl() const = 0;
+
+  virtual void SetSolenoids(int mask, int values) = 0;
+
+  virtual int GetSolenoids() const = 0;
+
+  virtual int GetModuleNumber() const = 0;
+
+  virtual int GetSolenoidDisabledList() const = 0;
+
+  virtual void FireOneShot(int index) = 0;
+
+  virtual void SetOneShotDuration(int index, units::second_t duration) = 0;
+
+  virtual bool CheckSolenoidChannel(int channel) const = 0;
+
+  virtual int CheckAndReserveSolenoids(int mask) = 0;
+
+  virtual void UnreserveSolenoids(int mask) = 0;
+
+  virtual bool ReserveCompressor() = 0;
+
+  virtual void UnreserveCompressor() = 0;
+
+  virtual Solenoid MakeSolenoid(int channel) = 0;
+  virtual DoubleSolenoid MakeDoubleSolenoid(int forwardChannel,
+                                            int reverseChannel) = 0;
+  virtual Compressor MakeCompressor() = 0;
+
+  static std::shared_ptr<PneumaticsBase> GetForType(
+      int module, PneumaticsModuleType moduleType);
+  static int GetDefaultForType(PneumaticsModuleType moduleType);
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PneumaticsControlModule.h b/wpilibc/src/main/native/include/frc/PneumaticsControlModule.h
new file mode 100644
index 0000000..64686d6
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/PneumaticsControlModule.h
@@ -0,0 +1,89 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <memory>
+
+#include <hal/Types.h>
+#include <wpi/DenseMap.h>
+#include <wpi/mutex.h>
+
+#include "PneumaticsBase.h"
+
+namespace frc {
+class PneumaticsControlModule : public PneumaticsBase {
+ public:
+  PneumaticsControlModule();
+  explicit PneumaticsControlModule(int module);
+
+  ~PneumaticsControlModule() override = default;
+
+  bool GetCompressor() const override;
+
+  void SetClosedLoopControl(bool enabled) override;
+
+  bool GetClosedLoopControl() const override;
+
+  bool GetPressureSwitch() const override;
+
+  double GetCompressorCurrent() const override;
+
+  bool GetCompressorCurrentTooHighFault() const;
+  bool GetCompressorCurrentTooHighStickyFault() const;
+  bool GetCompressorShortedFault() const;
+  bool GetCompressorShortedStickyFault() const;
+  bool GetCompressorNotConnectedFault() const;
+  bool GetCompressorNotConnectedStickyFault() const;
+
+  bool GetSolenoidVoltageFault() const;
+  bool GetSolenoidVoltageStickyFault() const;
+
+  void ClearAllStickyFaults();
+
+  void SetSolenoids(int mask, int values) override;
+
+  int GetSolenoids() const override;
+
+  int GetModuleNumber() const override;
+
+  int GetSolenoidDisabledList() const override;
+
+  void FireOneShot(int index) override;
+
+  void SetOneShotDuration(int index, units::second_t duration) override;
+
+  bool CheckSolenoidChannel(int channel) const override;
+
+  int CheckAndReserveSolenoids(int mask) override;
+
+  void UnreserveSolenoids(int mask) override;
+
+  bool ReserveCompressor() override;
+
+  void UnreserveCompressor() override;
+
+  Solenoid MakeSolenoid(int channel) override;
+  DoubleSolenoid MakeDoubleSolenoid(int forwardChannel,
+                                    int reverseChannel) override;
+  Compressor MakeCompressor() override;
+
+ private:
+  class DataStore;
+  friend class DataStore;
+  friend class PneumaticsBase;
+  PneumaticsControlModule(HAL_CTREPCMHandle handle, int module);
+
+  static std::shared_ptr<PneumaticsBase> GetForModule(int module);
+
+  std::shared_ptr<DataStore> m_dataStore;
+  HAL_CTREPCMHandle m_handle;
+  int m_module;
+
+  static wpi::mutex m_handleLock;
+  static std::unique_ptr<wpi::DenseMap<int, std::weak_ptr<DataStore>>>
+      m_handleMap;
+  static std::weak_ptr<DataStore>& GetDataStore(int module);
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PneumaticsModuleType.h b/wpilibc/src/main/native/include/frc/PneumaticsModuleType.h
new file mode 100644
index 0000000..7f70662
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/PneumaticsModuleType.h
@@ -0,0 +1,9 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+namespace frc {
+enum class PneumaticsModuleType { CTREPCM, REVPH };
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PowerDistribution.h b/wpilibc/src/main/native/include/frc/PowerDistribution.h
new file mode 100644
index 0000000..2863daf
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/PowerDistribution.h
@@ -0,0 +1,112 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <hal/Types.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
+namespace frc {
+
+/**
+ * Class for getting voltage, current, temperature, power and energy from the
+ * CAN PDP.
+ */
+class PowerDistribution : public wpi::Sendable,
+                          public wpi::SendableHelper<PowerDistribution> {
+ public:
+  static constexpr int kDefaultModule = -1;
+  enum class ModuleType { kAutomatic = 0, kCTRE = 1, kRev = 2 };
+
+  /**
+   * Constructs a PowerDistribution.
+   *
+   * Uses the default CAN ID.
+   */
+  PowerDistribution();
+
+  /**
+   * Constructs a PowerDistribution.
+   *
+   * @param module The CAN ID of the PDP
+   * @param moduleType The type of module
+   */
+  PowerDistribution(int module, ModuleType moduleType);
+
+  ~PowerDistribution() override;
+  PowerDistribution(PowerDistribution&&) = default;
+  PowerDistribution& operator=(PowerDistribution&&) = default;
+
+  /**
+   * Query the input voltage of the PDP.
+   *
+   * @return The voltage of the PDP in volts
+   */
+  double GetVoltage() const;
+
+  /**
+   * Query the temperature of the PDP.
+   *
+   * @return The temperature of the PDP in degrees Celsius
+   */
+  double GetTemperature() const;
+
+  /**
+   * Query the current of a single channel of the PDP.
+   *
+   * @return The current of one of the PDP channels (channels 0-15) in Amperes
+   */
+  double GetCurrent(int channel) const;
+
+  /**
+   * Query the total current of all monitored PDP channels (0-15).
+   *
+   * @return The the total current drawn from the PDP channels in Amperes
+   */
+  double GetTotalCurrent() const;
+
+  /**
+   * Query the total power drawn from the monitored PDP channels.
+   *
+   * @return The the total power drawn from the PDP channels in Watts
+   */
+  double GetTotalPower() const;
+
+  /**
+   * Query the total energy drawn from the monitored PDP channels.
+   *
+   * @return The the total energy drawn from the PDP channels in Joules
+   */
+  double GetTotalEnergy() const;
+
+  /**
+   * Reset the total energy drawn from the PDP.
+   *
+   * @see PowerDistribution#GetTotalEnergy
+   */
+  void ResetTotalEnergy();
+
+  /**
+   * Remove all of the fault flags on the PDP.
+   */
+  void ClearStickyFaults();
+
+  /**
+   * Gets module number (CAN ID).
+   */
+  int GetModule() const;
+
+  bool GetSwitchableChannel() const;
+
+  void SetSwitchableChannel(bool enabled);
+
+  void InitSendable(wpi::SendableBuilder& builder) override;
+
+ private:
+  hal::Handle<HAL_PowerDistributionHandle> m_handle;
+  int m_module;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PowerDistributionPanel.h b/wpilibc/src/main/native/include/frc/PowerDistributionPanel.h
deleted file mode 100644
index 9ec00a3..0000000
--- a/wpilibc/src/main/native/include/frc/PowerDistributionPanel.h
+++ /dev/null
@@ -1,100 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <hal/Types.h>
-
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
-
-namespace frc {
-
-class SendableBuilder;
-
-/**
- * Class for getting voltage, current, temperature, power and energy from the
- * CAN PDP.
- */
-class PowerDistributionPanel : public ErrorBase,
-                               public Sendable,
-                               public SendableHelper<PowerDistributionPanel> {
- public:
-  PowerDistributionPanel();
-  explicit PowerDistributionPanel(int module);
-
-  PowerDistributionPanel(PowerDistributionPanel&&) = default;
-  PowerDistributionPanel& operator=(PowerDistributionPanel&&) = default;
-
-  /**
-   * Query the input voltage of the PDP.
-   *
-   * @return The voltage of the PDP in volts
-   */
-  double GetVoltage() const;
-
-  /**
-   * Query the temperature of the PDP.
-   *
-   * @return The temperature of the PDP in degrees Celsius
-   */
-  double GetTemperature() const;
-
-  /**
-   * Query the current of a single channel of the PDP.
-   *
-   * @return The current of one of the PDP channels (channels 0-15) in Amperes
-   */
-  double GetCurrent(int channel) const;
-
-  /**
-   * Query the total current of all monitored PDP channels (0-15).
-   *
-   * @return The the total current drawn from the PDP channels in Amperes
-   */
-  double GetTotalCurrent() const;
-
-  /**
-   * Query the total power drawn from the monitored PDP channels.
-   *
-   * @return The the total power drawn from the PDP channels in Watts
-   */
-  double GetTotalPower() const;
-
-  /**
-   * Query the total energy drawn from the monitored PDP channels.
-   *
-   * @return The the total energy drawn from the PDP channels in Joules
-   */
-  double GetTotalEnergy() const;
-
-  /**
-   * Reset the total energy drawn from the PDP.
-   *
-   * @see PowerDistributionPanel#GetTotalEnergy
-   */
-  void ResetTotalEnergy();
-
-  /**
-   * Remove all of the fault flags on the PDP.
-   */
-  void ClearStickyFaults();
-
-  /**
-   * Gets module number (CAN ID).
-   */
-  int GetModule() const;
-
-  void InitSendable(SendableBuilder& builder) override;
-
- private:
-  hal::Handle<HAL_PDPHandle> m_handle;
-  int m_module;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Preferences.h b/wpilibc/src/main/native/include/frc/Preferences.h
index f04b012..b939d9e 100644
--- a/wpilibc/src/main/native/include/frc/Preferences.h
+++ b/wpilibc/src/main/native/include/frc/Preferences.h
@@ -1,21 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2011-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.
 
 #pragma once
 
 #include <stdint.h>
 
-#include <memory>
 #include <string>
+#include <string_view>
 #include <vector>
 
-#include <networktables/NetworkTable.h>
-
-#include "frc/ErrorBase.h"
+#include <wpi/deprecated.h>
 
 namespace frc {
 
@@ -30,16 +25,18 @@
  *
  * This class is thread safe.
  *
- * This will also interact with {@link NetworkTable} by creating a table called
+ * This will also interact with NetworkTable by creating a table called
  * "Preferences" with all the key-value pairs.
  */
-class Preferences : public ErrorBase {
+class Preferences {
  public:
   /**
    * Get the one and only {@link Preferences} object.
    *
    * @return pointer to the {@link Preferences}
+   * @deprecated Use the static methods
    */
+  WPI_DEPRECATED("Use static methods")
   static Preferences* GetInstance();
 
   /**
@@ -47,7 +44,7 @@
    *
    * @return a vector of the keys
    */
-  std::vector<std::string> GetKeys();
+  static std::vector<std::string> GetKeys();
 
   /**
    * Returns the string at the given key.  If this table does not have a value
@@ -57,7 +54,8 @@
    * @param defaultValue the value to return if none exists in the table
    * @return either the value in the table, or the defaultValue
    */
-  std::string GetString(wpi::StringRef key, wpi::StringRef defaultValue = "");
+  static std::string GetString(std::string_view key,
+                               std::string_view defaultValue = "");
 
   /**
    * Returns the int at the given key.  If this table does not have a value for
@@ -67,7 +65,7 @@
    * @param defaultValue the value to return if none exists in the table
    * @return either the value in the table, or the defaultValue
    */
-  int GetInt(wpi::StringRef key, int defaultValue = 0);
+  static int GetInt(std::string_view key, int defaultValue = 0);
 
   /**
    * Returns the double at the given key.  If this table does not have a value
@@ -77,7 +75,7 @@
    * @param defaultValue the value to return if none exists in the table
    * @return either the value in the table, or the defaultValue
    */
-  double GetDouble(wpi::StringRef key, double defaultValue = 0.0);
+  static double GetDouble(std::string_view key, double defaultValue = 0.0);
 
   /**
    * Returns the float at the given key.  If this table does not have a value
@@ -87,7 +85,7 @@
    * @param defaultValue the value to return if none exists in the table
    * @return either the value in the table, or the defaultValue
    */
-  float GetFloat(wpi::StringRef key, float defaultValue = 0.0);
+  static float GetFloat(std::string_view key, float defaultValue = 0.0);
 
   /**
    * Returns the boolean at the given key.  If this table does not have a value
@@ -97,7 +95,7 @@
    * @param defaultValue the value to return if none exists in the table
    * @return either the value in the table, or the defaultValue
    */
-  bool GetBoolean(wpi::StringRef key, bool defaultValue = false);
+  static bool GetBoolean(std::string_view key, bool defaultValue = false);
 
   /**
    * Returns the long (int64_t) at the given key.  If this table does not have a
@@ -108,7 +106,7 @@
    * @param defaultValue the value to return if none exists in the table
    * @return either the value in the table, or the defaultValue
    */
-  int64_t GetLong(wpi::StringRef key, int64_t defaultValue = 0);
+  static int64_t GetLong(std::string_view key, int64_t defaultValue = 0);
 
   /**
    * Puts the given string into the preferences table.
@@ -119,13 +117,25 @@
    * @param key   the key
    * @param value the value
    */
-  void PutString(wpi::StringRef key, wpi::StringRef value);
+  static void SetString(std::string_view key, std::string_view value);
+
+  /**
+   * Puts the given string into the preferences table.
+   *
+   * The value may not have quotation marks, nor may the key have any whitespace
+   * nor an equals sign.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  WPI_DEPRECATED("Use SetString instead.")
+  static void PutString(std::string_view key, std::string_view value);
 
   /**
    * Puts the given string into the preferences table if it doesn't
    * already exist.
    */
-  void InitString(wpi::StringRef key, wpi::StringRef value);
+  static void InitString(std::string_view key, std::string_view value);
 
   /**
    * Puts the given int into the preferences table.
@@ -135,13 +145,24 @@
    * @param key   the key
    * @param value the value
    */
-  void PutInt(wpi::StringRef key, int value);
+  static void SetInt(std::string_view key, int value);
+
+  /**
+   * Puts the given int into the preferences table.
+   *
+   * The key may not have any whitespace nor an equals sign.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  WPI_DEPRECATED("Use SetInt instead.")
+  static void PutInt(std::string_view key, int value);
 
   /**
    * Puts the given int into the preferences table if it doesn't
    * already exist.
    */
-  void InitInt(wpi::StringRef key, int value);
+  static void InitInt(std::string_view key, int value);
 
   /**
    * Puts the given double into the preferences table.
@@ -151,13 +172,24 @@
    * @param key   the key
    * @param value the value
    */
-  void PutDouble(wpi::StringRef key, double value);
+  static void SetDouble(std::string_view key, double value);
+
+  /**
+   * Puts the given double into the preferences table.
+   *
+   * The key may not have any whitespace nor an equals sign.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  WPI_DEPRECATED("Use SetDouble instead.")
+  static void PutDouble(std::string_view key, double value);
 
   /**
    * Puts the given double into the preferences table if it doesn't
    * already exist.
    */
-  void InitDouble(wpi::StringRef key, double value);
+  static void InitDouble(std::string_view key, double value);
 
   /**
    * Puts the given float into the preferences table.
@@ -167,13 +199,24 @@
    * @param key   the key
    * @param value the value
    */
-  void PutFloat(wpi::StringRef key, float value);
+  static void SetFloat(std::string_view key, float value);
+
+  /**
+   * Puts the given float into the preferences table.
+   *
+   * The key may not have any whitespace nor an equals sign.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  WPI_DEPRECATED("Use SetFloat instead.")
+  static void PutFloat(std::string_view key, float value);
 
   /**
    * Puts the given float into the preferences table if it doesn't
    * already exist.
    */
-  void InitFloat(wpi::StringRef key, float value);
+  static void InitFloat(std::string_view key, float value);
 
   /**
    * Puts the given boolean into the preferences table.
@@ -183,13 +226,24 @@
    * @param key   the key
    * @param value the value
    */
-  void PutBoolean(wpi::StringRef key, bool value);
+  static void SetBoolean(std::string_view key, bool value);
+
+  /**
+   * Puts the given boolean into the preferences table.
+   *
+   * The key may not have any whitespace nor an equals sign.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  WPI_DEPRECATED("Use SetBoolean instead.")
+  static void PutBoolean(std::string_view key, bool value);
 
   /**
    * Puts the given boolean into the preferences table if it doesn't
    * already exist.
    */
-  void InitBoolean(wpi::StringRef key, bool value);
+  static void InitBoolean(std::string_view key, bool value);
 
   /**
    * Puts the given long (int64_t) into the preferences table.
@@ -199,13 +253,24 @@
    * @param key   the key
    * @param value the value
    */
-  void PutLong(wpi::StringRef key, int64_t value);
+  static void SetLong(std::string_view key, int64_t value);
+
+  /**
+   * Puts the given long (int64_t) into the preferences table.
+   *
+   * The key may not have any whitespace nor an equals sign.
+   *
+   * @param key   the key
+   * @param value the value
+   */
+  WPI_DEPRECATED("Use SetLong instead.")
+  static void PutLong(std::string_view key, int64_t value);
 
   /**
    * Puts the given long into the preferences table if it doesn't
    * already exist.
    */
-  void InitLong(wpi::StringRef key, int64_t value);
+  static void InitLong(std::string_view key, int64_t value);
 
   /**
    * Returns whether or not there is a key with the given name.
@@ -213,30 +278,22 @@
    * @param key the key
    * @return if there is a value at the given key
    */
-  bool ContainsKey(wpi::StringRef key);
+  static bool ContainsKey(std::string_view key);
 
   /**
    * Remove a preference.
    *
    * @param key the key
    */
-  void Remove(wpi::StringRef key);
+  static void Remove(std::string_view key);
 
   /**
    * Remove all preferences.
    */
-  void RemoveAll();
-
- protected:
-  Preferences();
-  virtual ~Preferences() = default;
-
-  Preferences(Preferences&&) = default;
-  Preferences& operator=(Preferences&&) = default;
+  static void RemoveAll();
 
  private:
-  std::shared_ptr<nt::NetworkTable> m_table;
-  NT_EntryListener m_listener;
+  Preferences() = default;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Relay.h b/wpilibc/src/main/native/include/frc/Relay.h
index c903fc0..4765c64 100644
--- a/wpilibc/src/main/native/include/frc/Relay.h
+++ b/wpilibc/src/main/native/include/frc/Relay.h
@@ -1,26 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
+#include <string>
 
 #include <hal/Types.h>
-#include <wpi/raw_ostream.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
-#include "frc/ErrorBase.h"
 #include "frc/MotorSafety.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * Class for Spike style relay outputs.
  *
@@ -34,8 +28,8 @@
  * a solenoid).
  */
 class Relay : public MotorSafety,
-              public Sendable,
-              public SendableHelper<Relay> {
+              public wpi::Sendable,
+              public wpi::SendableHelper<Relay> {
  public:
   enum Value { kOff, kOn, kForward, kReverse };
   enum Direction { kBothDirections, kForwardOnly, kReverseOnly };
@@ -95,9 +89,9 @@
   // MotorSafety interface
   void StopMotor() override;
 
-  void GetDescription(wpi::raw_ostream& desc) const override;
+  std::string GetDescription() const override;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   int m_channel;
diff --git a/wpilibc/src/main/native/include/frc/Resource.h b/wpilibc/src/main/native/include/frc/Resource.h
index e9759d5..4109cc4 100644
--- a/wpilibc/src/main/native/include/frc/Resource.h
+++ b/wpilibc/src/main/native/include/frc/Resource.h
@@ -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.
 
 #pragma once
 
@@ -15,8 +12,6 @@
 
 #include <wpi/mutex.h>
 
-#include "frc/ErrorBase.h"
-
 namespace frc {
 
 /**
@@ -29,7 +24,7 @@
  * resources; it just tracks which indices were marked in use by Allocate and
  * not yet freed by Free.
  */
-class Resource : public ErrorBase {
+class Resource {
  public:
   virtual ~Resource() = default;
 
diff --git a/wpilibc/src/main/native/include/frc/RobotBase.h b/wpilibc/src/main/native/include/frc/RobotBase.h
index 66d5637..70c6093 100644
--- a/wpilibc/src/main/native/include/frc/RobotBase.h
+++ b/wpilibc/src/main/native/include/frc/RobotBase.h
@@ -1,39 +1,50 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <chrono>
 #include <thread>
 
+#include <hal/DriverStation.h>
 #include <hal/HALBase.h>
 #include <hal/Main.h>
 #include <wpi/condition_variable.h>
+#include <wpi/deprecated.h>
 #include <wpi/mutex.h>
-#include <wpi/raw_ostream.h>
 
-#include "frc/Base.h"
+#include "frc/Errors.h"
+#include "frc/RuntimeType.h"
 
 namespace frc {
 
-class DriverStation;
-
 int RunHALInitialization();
 
 namespace impl {
 
 template <class Robot>
 void RunRobot(wpi::mutex& m, Robot** robot) {
-  static Robot theRobot;
-  {
-    std::scoped_lock lock{m};
-    *robot = &theRobot;
+  try {
+    static Robot theRobot;
+    {
+      std::scoped_lock lock{m};
+      *robot = &theRobot;
+    }
+    theRobot.StartCompetition();
+  } catch (const frc::RuntimeError& e) {
+    e.Report();
+    FRC_ReportError(
+        err::Error, "{}",
+        "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");
+    throw;
+  } catch (const std::exception& e) {
+    HAL_SendError(1, err::Error, 0, e.what(), "", "", 1);
+    throw;
   }
-  theRobot.StartCompetition();
 }
 
 }  // namespace impl
@@ -77,15 +88,18 @@
     HAL_RunMain();
 
     // signal loop to exit
-    if (robot) robot->EndCompetition();
+    if (robot) {
+      robot->EndCompetition();
+    }
 
     // prefer to join, but detach to exit if it doesn't exit in a timely manner
     using namespace std::chrono_literals;
     std::unique_lock lock{m};
-    if (cv.wait_for(lock, 1s, [] { return exited; }))
+    if (cv.wait_for(lock, 1s, [] { return exited; })) {
       thr.join();
-    else
+    } else {
       thr.detach();
+    }
   } else {
     impl::RunRobot<Robot>(m, &robot);
   }
@@ -95,13 +109,6 @@
   return 0;
 }
 
-#define START_ROBOT_CLASS(_ClassName_)                                 \
-  WPI_DEPRECATED("Call frc::StartRobot<" #_ClassName_                  \
-                 ">() in your own main() instead of using the "        \
-                 "START_ROBOT_CLASS(" #_ClassName_ ") macro.")         \
-  int StartRobotClassImpl() { return frc::StartRobot<_ClassName_>(); } \
-  int main() { return StartRobotClassImpl(); }
-
 /**
  * Implement a Robot Program framework.
  *
@@ -149,16 +156,36 @@
    *
    * @return True if the robot is currently operating in Tele-Op mode as
    *         determined by the field controls.
+   * @deprecated Use IsTeleop() instead.
    */
+  WPI_DEPRECATED("Use IsTeleop() instead")
   bool IsOperatorControl() const;
 
   /**
+   * Determine if the robot is currently in Operator Control mode.
+   *
+   * @return True if the robot is currently operating in Tele-Op mode as
+   *         determined by the field controls.
+   */
+  bool IsTeleop() const;
+
+  /**
+   * Determine if the robot is current in Operator Control mode and enabled.
+   *
+   * @return True if the robot is currently operating in Tele-Op mode while
+   *         enabled as determined by the field-controls.
+   * @deprecated Use IsTeleopEnabled() instead.
+   */
+  WPI_DEPRECATED("Use IsTeleopEnabled() instead")
+  bool IsOperatorControlEnabled() const;
+
+  /**
    * Determine if the robot is current in Operator Control mode and enabled.
    *
    * @return True if the robot is currently operating in Tele-Op mode while
    * wnabled as determined by the field-controls.
    */
-  bool IsOperatorControlEnabled() const;
+  bool IsTeleopEnabled() const;
 
   /**
    * Determine if the robot is currently in Test mode.
@@ -186,6 +213,13 @@
   virtual void EndCompetition() = 0;
 
   /**
+   * Get the current runtime type.
+   *
+   * @return Current runtime type.
+   */
+  static RuntimeType GetRuntimeType();
+
+  /**
    * Get if the robot is real.
    *
    * @return If the robot is running in the real world.
@@ -218,15 +252,11 @@
    */
   RobotBase();
 
-  virtual ~RobotBase();
+  virtual ~RobotBase() = default;
 
  protected:
-  // m_ds isn't moved in these because DriverStation is a singleton; every
-  // instance of RobotBase has a reference to the same object.
-  RobotBase(RobotBase&&) noexcept;
-  RobotBase& operator=(RobotBase&&) noexcept;
-
-  DriverStation& m_ds;
+  RobotBase(RobotBase&&) = default;
+  RobotBase& operator=(RobotBase&&) = default;
 
   static std::thread::id m_threadId;
 };
diff --git a/wpilibc/src/main/native/include/frc/RobotController.h b/wpilibc/src/main/native/include/frc/RobotController.h
index fae136b..e9750f0 100644
--- a/wpilibc/src/main/native/include/frc/RobotController.h
+++ b/wpilibc/src/main/native/include/frc/RobotController.h
@@ -1,14 +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.
 
 #pragma once
 
 #include <stdint.h>
 
+#include <units/voltage.h>
+
 namespace frc {
 
 struct CANStatus {
@@ -59,6 +58,13 @@
   static bool GetUserButton();
 
   /**
+   * Read the battery voltage.
+   *
+   * @return The battery voltage in Volts.
+   */
+  static units::volt_t GetBatteryVoltage();
+
+  /**
    * Check if the FPGA outputs are enabled.
    *
    * The outputs may be disabled if the robot is disabled or e-stopped, the
@@ -182,6 +188,28 @@
    */
   static int GetFaultCount6V();
 
+  /**
+   * Get the current brownout voltage setting.
+   *
+   * @return The brownout voltage
+   */
+  static units::volt_t GetBrownoutVoltage();
+
+  /**
+   * Set the voltage the roboRIO will brownout and disable all outputs.
+   *
+   * Note that this only does anything on the roboRIO 2.
+   * On the roboRIO it is a no-op.
+   *
+   * @param brownoutVoltage The brownout voltage
+   */
+  static void SetBrownoutVoltage(units::volt_t brownoutVoltage);
+
+  /**
+   * Get the current status of the CAN bus.
+   *
+   * @return The status of the CAN bus
+   */
   static CANStatus GetCANStatus();
 };
 
diff --git a/wpilibc/src/main/native/include/frc/RobotDrive.h b/wpilibc/src/main/native/include/frc/RobotDrive.h
deleted file mode 100644
index a8b63e6..0000000
--- a/wpilibc/src/main/native/include/frc/RobotDrive.h
+++ /dev/null
@@ -1,456 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-
-#include <wpi/deprecated.h>
-#include <wpi/raw_ostream.h>
-
-#include "frc/ErrorBase.h"
-#include "frc/MotorSafety.h"
-
-namespace frc {
-
-class SpeedController;
-class GenericHID;
-
-/**
- * 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 passed
- * 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 DifferentialDrive or MecanumDrive classes instead.
- *
- */
-class RobotDrive : public MotorSafety {
- public:
-  enum MotorType {
-    kFrontLeftMotor = 0,
-    kFrontRightMotor = 1,
-    kRearLeftMotor = 2,
-    kRearRightMotor = 3
-  };
-
-  /**
-   * 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.
-   *                          0-9 are on-board, 10-19 are on the MXP port
-   * @param rightMotorChannel The PWM channel number that drives the right
-   *                          motor. 0-9 are on-board, 10-19 are on the MXP port
-   */
-  WPI_DEPRECATED("Use DifferentialDrive or MecanumDrive classes instead.")
-  RobotDrive(int leftMotorChannel, int rightMotorChannel);
-
-  /**
-   * 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. 0-9 are on-board,
-   *                        10-19 are on the MXP port
-   * @param rearLeftMotor   Rear Left motor channel number. 0-9 are on-board,
-   *                        10-19 are on the MXP port
-   * @param frontRightMotor Front right motor channel number. 0-9 are on-board,
-   *                        10-19 are on the MXP port
-   * @param rearRightMotor  Rear Right motor channel number. 0-9 are on-board,
-   *                        10-19 are on the MXP port
-   */
-  WPI_DEPRECATED("Use DifferentialDrive or MecanumDrive classes instead.")
-  RobotDrive(int frontLeftMotorChannel, int rearLeftMotorChannel,
-             int frontRightMotorChannel, int rearRightMotorChannel);
-
-  /**
-   * 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 deadband elimination.
-   *
-   * @param leftMotor  The left SpeedController object used to drive the robot.
-   * @param rightMotor The right SpeedController object used to drive the robot.
-   */
-  WPI_DEPRECATED("Use DifferentialDrive or MecanumDrive classes instead.")
-  RobotDrive(SpeedController* leftMotor, SpeedController* rightMotor);
-
-  WPI_DEPRECATED("Use DifferentialDrive or MecanumDrive classes instead.")
-  RobotDrive(SpeedController& leftMotor, SpeedController& rightMotor);
-
-  WPI_DEPRECATED("Use DifferentialDrive or MecanumDrive classes instead.")
-  RobotDrive(std::shared_ptr<SpeedController> leftMotor,
-             std::shared_ptr<SpeedController> rightMotor);
-
-  /**
-   * 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.
-   */
-  WPI_DEPRECATED("Use DifferentialDrive or MecanumDrive classes instead.")
-  RobotDrive(SpeedController* frontLeftMotor, SpeedController* rearLeftMotor,
-             SpeedController* frontRightMotor, SpeedController* rearRightMotor);
-
-  WPI_DEPRECATED("Use DifferentialDrive or MecanumDrive classes instead.")
-  RobotDrive(SpeedController& frontLeftMotor, SpeedController& rearLeftMotor,
-             SpeedController& frontRightMotor, SpeedController& rearRightMotor);
-
-  WPI_DEPRECATED("Use DifferentialDrive or MecanumDrive classes instead.")
-  RobotDrive(std::shared_ptr<SpeedController> frontLeftMotor,
-             std::shared_ptr<SpeedController> rearLeftMotor,
-             std::shared_ptr<SpeedController> frontRightMotor,
-             std::shared_ptr<SpeedController> rearRightMotor);
-
-  virtual ~RobotDrive() = default;
-
-  RobotDrive(RobotDrive&&) = default;
-  RobotDrive& operator=(RobotDrive&&) = default;
-
-  /**
-   * 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. curve < 0 will turn left and curve > 0
-   * will turn right.
-   *
-   * The algorithm for steering provides a constant turn radius for any normal
-   * speed range, both forward and backward. Increasing m_sensitivity causes
-   * sharper turns for fixed values of curve.
-   *
-   * 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 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.
-   */
-  void Drive(double outputMagnitude, double curve);
-
-  /**
-   * 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 If true, the sensitivity will be decreased for small
-   *                      values
-   */
-  void TankDrive(GenericHID* leftStick, GenericHID* rightStick,
-                 bool squaredInputs = 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 If true, the sensitivity will be decreased for small
-   *                      values
-   */
-  void TankDrive(GenericHID& leftStick, GenericHID& rightStick,
-                 bool squaredInputs = 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 If true, the sensitivity will be decreased for small
-   *                      values
-   */
-  void TankDrive(GenericHID* leftStick, int leftAxis, GenericHID* rightStick,
-                 int rightAxis, bool squaredInputs = true);
-
-  void TankDrive(GenericHID& leftStick, int leftAxis, GenericHID& rightStick,
-                 int rightAxis, bool squaredInputs = true);
-
-  /**
-   * 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 If true, the sensitivity will be decreased for small
-   *                      values
-   */
-  void TankDrive(double leftValue, double rightValue,
-                 bool squaredInputs = 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
-   */
-  void ArcadeDrive(GenericHID* stick, bool squaredInputs = 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
-   */
-  void ArcadeDrive(GenericHID& stick, bool squaredInputs = 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 increases the
-   *                      sensitivity at lower speeds
-   */
-  void ArcadeDrive(GenericHID* moveStick, int moveChannel,
-                   GenericHID* rotateStick, int rotateChannel,
-                   bool squaredInputs = 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 increases the
-   *                      sensitivity at lower speeds
-   */
-  void ArcadeDrive(GenericHID& moveStick, int moveChannel,
-                   GenericHID& rotateStick, int rotateChannel,
-                   bool squaredInputs = 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 fowards/backwards
-   * @param rotateValue   The value to use for the rotate right/left
-   * @param squaredInputs If set, increases the sensitivity at low speeds
-   */
-  void ArcadeDrive(double moveValue, double rotateValue,
-                   bool squaredInputs = true);
-
-  /**
-   * Drive method for Mecanum wheeled robots.
-   *
-   * 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.
-   *
-   * 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.
-   */
-  void MecanumDrive_Cartesian(double x, double y, double rotation,
-                              double gyroAngle = 0.0);
-
-  /**
-   * Drive method for Mecanum wheeled robots.
-   *
-   * 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 direction the robot should drive in degrees. The
-   *                  direction and maginitute 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 MecanumDrive_Polar(double magnitude, double direction, double rotation);
-
-  /**
-   * Holonomic Drive method for Mecanum wheeled robots.
-   *
-   * 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
-   *                  magnitude are independent of the rotation rate.
-   * @param rotation  The rate of rotation for the robot that is completely
-   *                  independent of the magnitude or direction.  [-1.0..1.0]
-   */
-  void HolonomicDrive(double magnitude, double direction, double 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 "leftOutput" and "rightOutput"
-   * 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.
-   */
-  virtual void SetLeftRightMotorOutputs(double leftOutput, double rightOutput);
-
-  /*
-   * 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.
-   */
-  void SetInvertedMotor(MotorType motor, bool isInverted);
-
-  /**
-   * Set the turning sensitivity.
-   *
-   * This only impacts the Drive() entry-point.
-   *
-   * @param sensitivity Effectively sets the turning sensitivity (or turn radius
-   *                    for a given value)
-   */
-  void SetSensitivity(double 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.
-   */
-  void SetMaxOutput(double maxOutput);
-
-  void StopMotor() override;
-  void GetDescription(wpi::raw_ostream& desc) const override;
-
- protected:
-  /**
-   * Common function to initialize all the robot drive constructors.
-   *
-   * Create a motor safety object (the real reason for the common code) and
-   * initialize all the motor assignments. The default timeout is set for the
-   * robot drive.
-   */
-  void InitRobotDrive();
-
-  /**
-   * Limit motor values to the -1.0 to +1.0 range.
-   */
-  double Limit(double number);
-
-  /**
-   * Normalize all wheel speeds if the magnitude of any wheel is greater than
-   * 1.0.
-   */
-  void Normalize(double* wheelSpeeds);
-
-  /**
-   * Rotate a vector in Cartesian space.
-   */
-  void RotateVector(double& x, double& y, double angle);
-
-  static constexpr int kMaxNumberOfMotors = 4;
-
-  double m_sensitivity = 0.5;
-  double m_maxOutput = 1.0;
-
-  std::shared_ptr<SpeedController> m_frontLeftMotor;
-  std::shared_ptr<SpeedController> m_frontRightMotor;
-  std::shared_ptr<SpeedController> m_rearLeftMotor;
-  std::shared_ptr<SpeedController> m_rearRightMotor;
-
- private:
-  int GetNumMotors() {
-    int motors = 0;
-    if (m_frontLeftMotor) motors++;
-    if (m_frontRightMotor) motors++;
-    if (m_rearLeftMotor) motors++;
-    if (m_rearRightMotor) motors++;
-    return motors;
-  }
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/RobotState.h b/wpilibc/src/main/native/include/frc/RobotState.h
index 5f1c136..cb97b13 100644
--- a/wpilibc/src/main/native/include/frc/RobotState.h
+++ b/wpilibc/src/main/native/include/frc/RobotState.h
@@ -1,12 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
+#include <wpi/deprecated.h>
+
 namespace frc {
 
 class RobotState {
@@ -16,7 +15,9 @@
   static bool IsDisabled();
   static bool IsEnabled();
   static bool IsEStopped();
+  WPI_DEPRECATED("Use IsTeleop() instead")
   static bool IsOperatorControl();
+  static bool IsTeleop();
   static bool IsAutonomous();
   static bool IsTest();
 };
diff --git a/wpilibc/src/main/native/include/frc/RuntimeType.h b/wpilibc/src/main/native/include/frc/RuntimeType.h
new file mode 100644
index 0000000..c3a8a0b
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/RuntimeType.h
@@ -0,0 +1,9 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+namespace frc {
+enum RuntimeType { kRoboRIO, kRoboRIO2, kSimulation };
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/SPI.h b/wpilibc/src/main/native/include/frc/SPI.h
index 3592775..36c82e4 100644
--- a/wpilibc/src/main/native/include/frc/SPI.h
+++ b/wpilibc/src/main/native/include/frc/SPI.h
@@ -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.
 
 #pragma once
 
@@ -13,10 +10,8 @@
 
 #include <hal/SPITypes.h>
 #include <units/time.h>
-#include <wpi/ArrayRef.h>
 #include <wpi/deprecated.h>
-
-#include "frc/ErrorBase.h"
+#include <wpi/span.h>
 
 namespace frc {
 
@@ -29,7 +24,7 @@
  * It probably should not be used directly.
  *
  */
-class SPI : public ErrorBase {
+class SPI {
  public:
   enum Port { kOnboardCS0 = 0, kOnboardCS1, kOnboardCS2, kOnboardCS3, kMXP };
 
@@ -40,11 +35,13 @@
    */
   explicit SPI(Port port);
 
-  ~SPI() override;
+  ~SPI();
 
   SPI(SPI&&) = default;
   SPI& operator=(SPI&&) = default;
 
+  Port GetPort() const;
+
   /**
    * Configure the rate of the generated clock signal.
    *
@@ -138,10 +135,12 @@
    * 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 Buffer to receive data from the device
+   * @param size         The length of the transaction, in bytes
    */
   virtual int Read(bool initiate, uint8_t* dataReceived, int size);
 
@@ -178,7 +177,7 @@
    * @param dataToSend data to send (maximum 16 bytes)
    * @param zeroSize number of zeros to send after the data
    */
-  void SetAutoTransmitData(wpi::ArrayRef<uint8_t> dataToSend, int zeroSize);
+  void SetAutoTransmitData(wpi::span<const uint8_t> dataToSend, int zeroSize);
 
   /**
    * Start running the automatic SPI transfer engine at a periodic rate.
@@ -248,32 +247,6 @@
                            units::second_t timeout);
 
   /**
-   * Read data that has been transferred by the automatic SPI transfer engine.
-   *
-   * 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.
-   *
-   * 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().
-   *
-   * Blocks until numToRead words have been read or timeout expires.
-   * May be called with numToRead=0 to retrieve how many words are available.
-   *
-   * @deprecated Use unit safe version instead.
-   *             ReadAutoReceivedData(uint32_t* buffer, int numToRead, <!--
-   * -->         units::second_t timeout)
-   *
-   * @param buffer buffer where read words are stored
-   * @param numToRead number of words to read
-   * @param timeout timeout in seconds (ms resolution)
-   * @return Number of words remaining to be read
-   */
-  WPI_DEPRECATED("Use ReadAutoReceivedData with unit-safety instead")
-  int ReadAutoReceivedData(uint32_t* buffer, int numToRead, double timeout);
-
-  /**
    * Get the number of bytes dropped by the automatic SPI transfer engine due
    * to the receive buffer being full.
    *
@@ -297,17 +270,17 @@
   /**
    * 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 validData After valid_mask 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 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 valid_mask 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?
    */
   void InitAccumulator(units::second_t period, int cmd, int xferSize,
                        int validMask, int validValue, int dataShift,
@@ -321,17 +294,17 @@
    * -->         xferSize, int validMask, int validValue, int dataShift, <!--
    * -->         int dataSize, bool isSigned, bool bigEndian)
    *
-   * @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 validData After valid_mask 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 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 valid_mask 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?
    */
   WPI_DEPRECATED("Use InitAccumulator with unit-safety instead")
   void InitAccumulator(double period, int cmd, int xferSize, int validMask,
diff --git a/wpilibc/src/main/native/include/frc/ScopedTracer.h b/wpilibc/src/main/native/include/frc/ScopedTracer.h
index 8634c1e..e700616 100644
--- a/wpilibc/src/main/native/include/frc/ScopedTracer.h
+++ b/wpilibc/src/main/native/include/frc/ScopedTracer.h
@@ -1,16 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <string>
-
-#include <wpi/StringRef.h>
-#include <wpi/Twine.h>
+#include <string_view>
 
 #include "frc/Tracer.h"
 
@@ -34,7 +29,7 @@
    * @param name The name of the epoch.
    * @param os A reference to the raw_ostream to print data to.
    */
-  ScopedTracer(wpi::Twine name, wpi::raw_ostream& os);
+  ScopedTracer(std::string_view name, wpi::raw_ostream& os);
   ~ScopedTracer();
 
   ScopedTracer(const ScopedTracer&) = delete;
diff --git a/wpilibc/src/main/native/include/frc/SensorUtil.h b/wpilibc/src/main/native/include/frc/SensorUtil.h
index ab471b1..60536b1 100644
--- a/wpilibc/src/main/native/include/frc/SensorUtil.h
+++ b/wpilibc/src/main/native/include/frc/SensorUtil.h
@@ -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.
 
 #pragma once
 
@@ -22,14 +19,14 @@
    *
    * @return The number of the default solenoid module.
    */
-  static int GetDefaultSolenoidModule();
+  static int GetDefaultCTREPCMModule();
 
   /**
-   * Check that the solenoid module number is valid. module numbers are 0-based
+   * Get the number of the default solenoid module.
    *
-   * @return Solenoid module is valid and present
+   * @return The number of the default solenoid module.
    */
-  static bool CheckSolenoidModule(int moduleNumber);
+  static int GetDefaultREVPHModule();
 
   /**
    * Check that the digital channel number is valid.
@@ -81,36 +78,11 @@
    */
   static bool CheckAnalogOutputChannel(int channel);
 
-  /**
-   * Verify that the solenoid channel number is within limits.
-   *
-   * @return Solenoid channel is valid
-   */
-  static bool CheckSolenoidChannel(int channel);
-
-  /**
-   * Verify that the power distribution channel number is within limits.
-   *
-   * @return PDP channel is valid
-   */
-  static bool CheckPDPChannel(int channel);
-
-  /**
-   * Verify that the PDP module number is within limits. module numbers are
-   * 0-based
-   *
-   * @return PDP module is valid
-   */
-  static bool CheckPDPModule(int module);
-
   static const int kDigitalChannels;
   static const int kAnalogInputs;
   static const int kAnalogOutputs;
-  static const int kSolenoidChannels;
-  static const int kSolenoidModules;
   static const int kPwmChannels;
   static const int kRelayChannels;
-  static const int kPDPChannels;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/SerialPort.h b/wpilibc/src/main/native/include/frc/SerialPort.h
index 7c44c75..7fff14a 100644
--- a/wpilibc/src/main/native/include/frc/SerialPort.h
+++ b/wpilibc/src/main/native/include/frc/SerialPort.h
@@ -1,20 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <string>
+#include <string_view>
 
 #include <hal/Types.h>
-#include <wpi/StringRef.h>
-#include <wpi/Twine.h>
-#include <wpi/deprecated.h>
-
-#include "frc/ErrorBase.h"
+#include <units/time.h>
 
 namespace frc {
 
@@ -30,7 +24,7 @@
  * and the NI-VISA Programmer's Reference Manual here:
  *   http://www.ni.com/pdf/manuals/370132c.pdf
  */
-class SerialPort : public ErrorBase {
+class SerialPort {
  public:
   enum Parity {
     kParity_None = 0,
@@ -68,8 +62,9 @@
    * @param stopBits The number of stop bits to use as defined by the enum
    *                 StopBits.
    */
-  SerialPort(int baudRate, Port port = kOnboard, int dataBits = 8,
-             Parity parity = kParity_None, StopBits stopBits = kStopBits_One);
+  explicit SerialPort(int baudRate, Port port = kOnboard, int dataBits = 8,
+                      Parity parity = kParity_None,
+                      StopBits stopBits = kStopBits_One);
 
   /**
    * Create an instance of a Serial Port class.
@@ -86,7 +81,7 @@
    * @param stopBits The number of stop bits to use as defined by the enum
    *                 StopBits.
    */
-  SerialPort(int baudRate, const wpi::Twine& portName, Port port = kOnboard,
+  SerialPort(int baudRate, std::string_view portName, Port port = kOnboard,
              int dataBits = 8, Parity parity = kParity_None,
              StopBits stopBits = kStopBits_One);
 
@@ -149,10 +144,10 @@
    * Use Write({data, len}) to get a buffer that is shorter than the length of
    * the string.
    *
-   * @param buffer StringRef to the buffer to read the bytes from.
+   * @param buffer the buffer to read the bytes from.
    * @return The number of bytes actually written into the port.
    */
-  int Write(wpi::StringRef buffer);
+  int Write(std::string_view buffer);
 
   /**
    * Configure the timeout of the serial port.
@@ -160,9 +155,9 @@
    * This defines the timeout for transactions with the hardware.
    * It will affect reads and very large writes.
    *
-   * @param timeout The number of seconds to to wait for I/O.
+   * @param timeout The time to wait for I/O.
    */
-  void SetTimeout(double timeout);
+  void SetTimeout(units::second_t timeout);
 
   /**
    * Specify the size of the input buffer.
diff --git a/wpilibc/src/main/native/include/frc/Servo.h b/wpilibc/src/main/native/include/frc/Servo.h
index 16b4281..b1df655 100644
--- a/wpilibc/src/main/native/include/frc/Servo.h
+++ b/wpilibc/src/main/native/include/frc/Servo.h
@@ -1,14 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include "frc/PWM.h"
-#include "frc/SpeedController.h"
 
 namespace frc {
 
@@ -68,7 +64,7 @@
    * X being set and angles of more than Y degrees result in an angle of Y being
    * set.
    *
-   * @param degrees The angle in degrees to set the servo.
+   * @param angle The angle in degrees to set the servo.
    */
   void SetAngle(double angle);
 
@@ -96,7 +92,7 @@
    */
   double GetMinAngle() const;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   double GetServoAngleRange() const;
diff --git a/wpilibc/src/main/native/include/frc/SlewRateLimiter.h b/wpilibc/src/main/native/include/frc/SlewRateLimiter.h
deleted file mode 100644
index d18fb09..0000000
--- a/wpilibc/src/main/native/include/frc/SlewRateLimiter.h
+++ /dev/null
@@ -1,76 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <frc2/Timer.h>
-
-#include <algorithm>
-
-#include <units/time.h>
-
-namespace frc {
-/**
- * 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 TrapezoidProfile
- * instead.
- *
- * @see TrapezoidProfile
- */
-template <class Unit>
-class SlewRateLimiter {
- public:
-  using Unit_t = units::unit_t<Unit>;
-  using Rate = units::compound_unit<Unit, units::inverse<units::seconds>>;
-  using Rate_t = units::unit_t<Rate>;
-
-  /**
-   * Creates a new SlewRateLimiter with the given rate limit and initial value.
-   *
-   * @param rateLimit The rate-of-change limit.
-   * @param initialValue The initial value of the input.
-   */
-  explicit SlewRateLimiter(Rate_t rateLimit, Unit_t initialValue = Unit_t{0})
-      : m_rateLimit{rateLimit},
-        m_prevVal{initialValue},
-        m_prevTime{frc2::Timer::GetFPGATimestamp()} {}
-
-  /**
-   * 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.
-   */
-  Unit_t Calculate(Unit_t input) {
-    units::second_t currentTime = frc2::Timer::GetFPGATimestamp();
-    units::second_t elapsedTime = currentTime - m_prevTime;
-    m_prevVal += std::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.
-   */
-  void Reset(Unit_t value) {
-    m_prevVal = value;
-    m_prevTime = frc2::Timer::GetFPGATimestamp();
-  }
-
- private:
-  Rate_t m_rateLimit;
-  Unit_t m_prevVal;
-  units::second_t m_prevTime;
-};
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Solenoid.h b/wpilibc/src/main/native/include/frc/Solenoid.h
index 9939b41..a09ffc0 100644
--- a/wpilibc/src/main/native/include/frc/Solenoid.h
+++ b/wpilibc/src/main/native/include/frc/Solenoid.h
@@ -1,46 +1,46 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <hal/Types.h>
+#include <memory>
 
-#include "frc/SolenoidBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <hal/Types.h>
+#include <units/time.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
+#include "frc/PneumaticsBase.h"
+#include "frc/PneumaticsModuleType.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
- * Solenoid class for running high voltage Digital Output (PCM).
+ * Solenoid class for running high voltage Digital Output on a pneumatics
+ * module.
  *
  * The Solenoid class is typically used for pneumatics solenoids, but could be
- * used for any device within the current spec of the PCM.
+ * used for any device within the current spec of the module.
  */
-class Solenoid : public SolenoidBase,
-                 public Sendable,
-                 public SendableHelper<Solenoid> {
+class Solenoid : public wpi::Sendable, public wpi::SendableHelper<Solenoid> {
  public:
   /**
-   * Constructor using the default PCM ID (0).
+   * Constructs a solenoid for a specified module and type.
    *
-   * @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.
    */
-  explicit Solenoid(int channel);
+  Solenoid(int module, PneumaticsModuleType moduleType, int channel);
 
   /**
-   * Constructor.
+   * Constructs a solenoid for a default module and specified 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 moduleType The module type to use.
+   * @param channel The channel the solenoid is on.
    */
-  Solenoid(int moduleNumber, int channel);
+  Solenoid(PneumaticsModuleType moduleType, int channel);
 
   ~Solenoid() override;
 
@@ -70,42 +70,47 @@
   void Toggle();
 
   /**
-   * Check if solenoid is blacklisted.
+   * Get the channel this solenoid is connected to.
+   */
+  int GetChannel() const;
+
+  /**
+   * Check if solenoid is Disabled.
    *
-   * If a solenoid is shorted, it is added to the blacklist and
+   * If a solenoid is shorted, it is added to the DisabledList and
    * disabled until power cycle, or until faults are cleared.
    *
    * @see ClearAllPCMStickyFaults()
    *
    * @return If solenoid is disabled due to short.
    */
-  bool IsBlackListed() const;
+  bool IsDisabled() const;
 
   /**
    * 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.
+   * @param duration The duration of the pulse, from 0.01 to 2.55 seconds.
    *
    * @see startPulse()
    */
-  void SetPulseDuration(double durationSeconds);
+  void SetPulseDuration(units::second_t duration);
 
   /**
-   * Trigger the PCM to generate a pulse of the duration set in
+   * %Trigger the PCM to generate a pulse of the duration set in
    * setPulseDuration.
    *
    * @see setPulseDuration()
    */
   void StartPulse();
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
-  hal::Handle<HAL_SolenoidHandle> m_solenoidHandle;
-  int m_channel;  // The channel on the module to control
+  std::shared_ptr<PneumaticsBase> m_module;
+  int m_mask;
+  int m_channel;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/SolenoidBase.h b/wpilibc/src/main/native/include/frc/SolenoidBase.h
deleted file mode 100644
index 314df5c..0000000
--- a/wpilibc/src/main/native/include/frc/SolenoidBase.h
+++ /dev/null
@@ -1,127 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/ErrorBase.h"
-
-namespace frc {
-
-/**
- * SolenoidBase class is the common base class for the Solenoid and
- * DoubleSolenoid classes.
- */
-class SolenoidBase : public ErrorBase {
- public:
-  /**
-   * Read all 8 solenoids as a single byte
-   *
-   * @param module the module to read from
-   * @return The current value of all 8 solenoids on the module.
-   */
-  static int GetAll(int module);
-
-  /**
-   * Read all 8 solenoids as a single byte
-   *
-   * @return The current value of all 8 solenoids on the module.
-   */
-  int GetAll() const;
-
-  /**
-   * 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.
-   * @see ClearAllPCMStickyFaults()
-   *
-   * @param module the module to read from
-   * @return The solenoid blacklist of all 8 solenoids on the module.
-   */
-  static int GetPCMSolenoidBlackList(int module);
-
-  /**
-   * 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.
-   * @see ClearAllPCMStickyFaults()
-   *
-   * @return The solenoid blacklist of all 8 solenoids on the module.
-   */
-  int GetPCMSolenoidBlackList() const;
-
-  /**
-   * @param module the module to read from
-   * @return true if PCM sticky fault is set : The common highside solenoid
-   *         voltage rail is too low, most likely a solenoid channel is shorted.
-   */
-  static bool GetPCMSolenoidVoltageStickyFault(int module);
-
-  /**
-   * @return true if PCM sticky fault is set : The common highside solenoid
-   *         voltage rail is too low, most likely a solenoid channel is shorted.
-   */
-  bool GetPCMSolenoidVoltageStickyFault() const;
-
-  /**
-   * @param module the module to read from
-   * @return true if PCM is in fault state : The common highside solenoid
-   *         voltage rail is too low, most likely a solenoid channel is shorted.
-   */
-  static bool GetPCMSolenoidVoltageFault(int module);
-
-  /**
-   * @return true if PCM is in fault state : The common highside solenoid
-   *         voltage rail is too low, most likely a solenoid channel is shorted.
-   */
-  bool GetPCMSolenoidVoltageFault() const;
-
-  /**
-   * Clear ALL sticky faults inside PCM that Compressor is wired to.
-   *
-   * 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.
-   *
-   * If no sticky faults are set then this call will have no effect.
-   *
-   * @param module the module to read from
-   */
-  static void ClearAllPCMStickyFaults(int module);
-
-  /**
-   * Clear ALL sticky faults inside PCM that Compressor is wired to.
-   *
-   * 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.
-   *
-   * If no sticky faults are set then this call will have no effect.
-   */
-  void ClearAllPCMStickyFaults();
-
- protected:
-  /**
-   * Constructor.
-   *
-   * @param moduleNumber The CAN PCM ID.
-   */
-  explicit SolenoidBase(int pcmID);
-
-  SolenoidBase(SolenoidBase&&) = default;
-  SolenoidBase& operator=(SolenoidBase&&) = default;
-
-  static constexpr int m_maxModules = 63;
-  static constexpr int m_maxPorts = 8;
-
-  int m_moduleNumber;  // PCM module number
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/SpeedController.h b/wpilibc/src/main/native/include/frc/SpeedController.h
index 3053c3b..8473015 100644
--- a/wpilibc/src/main/native/include/frc/SpeedController.h
+++ b/wpilibc/src/main/native/include/frc/SpeedController.h
@@ -1,22 +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.
 
 #pragma once
 
 #include <units/voltage.h>
-
-#include "frc/PIDOutput.h"
+#include <wpi/deprecated.h>
 
 namespace frc {
 
 /**
  * Interface for speed controlling devices.
+ *
+ * @deprecated Use MotorController.
  */
-class SpeedController : public PIDOutput {
+class WPI_DEPRECATED("use MotorController") SpeedController {
  public:
   virtual ~SpeedController() = default;
 
diff --git a/wpilibc/src/main/native/include/frc/SpeedControllerGroup.h b/wpilibc/src/main/native/include/frc/SpeedControllerGroup.h
index e62563c..5a097b5 100644
--- a/wpilibc/src/main/native/include/frc/SpeedControllerGroup.h
+++ b/wpilibc/src/main/native/include/frc/SpeedControllerGroup.h
@@ -1,24 +1,29 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <functional>
 #include <vector>
 
-#include "frc/SpeedController.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <wpi/deprecated.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
+#include "frc/motorcontrol/MotorController.h"
 
 namespace frc {
 
-class SpeedControllerGroup : public Sendable,
-                             public SpeedController,
-                             public SendableHelper<SpeedControllerGroup> {
+/**
+ * Allows multiple SpeedController objects to be linked together.
+ *
+ * @deprecated Use MotorControllerGroup.
+ */
+class WPI_DEPRECATED("use MotorControllerGroup") SpeedControllerGroup
+    : public wpi::Sendable,
+      public MotorController,
+      public wpi::SendableHelper<SpeedControllerGroup> {
  public:
   template <class... SpeedControllers>
   explicit SpeedControllerGroup(SpeedController& speedController,
@@ -35,9 +40,8 @@
   bool GetInverted() const override;
   void Disable() override;
   void StopMotor() override;
-  void PIDWrite(double output) override;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   bool m_isInverted = false;
diff --git a/wpilibc/src/main/native/include/frc/SpeedControllerGroup.inc b/wpilibc/src/main/native/include/frc/SpeedControllerGroup.inc
index d9e773d..d5f17b4 100644
--- a/wpilibc/src/main/native/include/frc/SpeedControllerGroup.inc
+++ b/wpilibc/src/main/native/include/frc/SpeedControllerGroup.inc
@@ -1,15 +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.
 
 #pragma once
 
 #include <functional>
 #include <vector>
 
+#include "frc/SpeedControllerGroup.h"
+
 namespace frc {
 
 template <class... SpeedControllers>
diff --git a/wpilibc/src/main/native/include/frc/SynchronousInterrupt.h b/wpilibc/src/main/native/include/frc/SynchronousInterrupt.h
new file mode 100644
index 0000000..03cc4f8
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/SynchronousInterrupt.h
@@ -0,0 +1,106 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <memory>
+
+#include <hal/Types.h>
+#include <units/time.h>
+
+namespace frc {
+class DigitalSource;
+
+/**
+ * Class for handling synchronous (blocking) interrupts.
+ *
+ * <p> By default, interrupts will occur on rising edge.
+ *
+ * <p> Asynchronous interrupts are handled by the AsynchronousInterrupt class.
+ */
+class SynchronousInterrupt {
+ public:
+  enum WaitResult {
+    kTimeout = 0x0,
+    kRisingEdge = 0x1,
+    kFallingEdge = 0x100,
+    kBoth = 0x101,
+  };
+
+  /**
+   * Construct a Synchronous Interrupt from a Digital Source.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   */
+  explicit SynchronousInterrupt(DigitalSource& source);
+
+  /**
+   * Construct a Synchronous Interrupt from a Digital Source.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   */
+  explicit SynchronousInterrupt(DigitalSource* source);
+
+  /**
+   * Construct a Synchronous Interrupt from a Digital Source.
+   *
+   * @param source the DigitalSource the interrupts are triggered from
+   */
+  explicit SynchronousInterrupt(std::shared_ptr<DigitalSource> source);
+
+  ~SynchronousInterrupt();
+
+  SynchronousInterrupt(SynchronousInterrupt&&) = default;
+  SynchronousInterrupt& operator=(SynchronousInterrupt&&) = default;
+
+  /**
+   * Wait for an interrupt to occur.
+   *
+   * <p> Both rising and falling edge can be returned if both a rising and
+   * falling happened between calls, and ignorePrevious is false.
+   *
+   * @param timeout The timeout to wait for. 0s or less will return immediately.
+   * @param ignorePrevious True to ignore any previous interrupts, false to
+   * return interrupt value if an interrupt has occured since last call.
+   * @return The edge(s) that were triggered, or timeout.
+   */
+  WaitResult WaitForInterrupt(units::second_t timeout,
+                              bool ignorePrevious = true);
+
+  /**
+   * Set which edges cause an interrupt to occur.
+   *
+   * @param risingEdge true to trigger on rising edge, false otherwise.
+   * @param fallingEdge true to trigger on falling edge, false otherwise
+   */
+  void SetInterruptEdges(bool risingEdge, bool fallingEdge);
+
+  /**
+   * Get the timestamp (relative to FPGA Time) of the last rising edge.
+   *
+   * @return the timestamp in seconds relative to getFPGATime
+   */
+  units::second_t 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
+   */
+  units::second_t GetFallingTimestamp();
+
+  /**
+   * Wake up an existing wait call. Can be called from any thread.
+   */
+  void WakeupWaitingInterrupt();
+
+ private:
+  void InitSynchronousInterrupt();
+  std::shared_ptr<DigitalSource> m_source;
+  hal::Handle<HAL_InterruptHandle> m_handle;
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Talon.h b/wpilibc/src/main/native/include/frc/Talon.h
deleted file mode 100644
index 6e92dfc..0000000
--- a/wpilibc/src/main/native/include/frc/Talon.h
+++ /dev/null
@@ -1,44 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/PWMSpeedController.h"
-
-namespace frc {
-
-/**
- * Cross the Road Electronics (CTRE) Talon and Talon SR Speed Controller.
- *
- * 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.
- *
- * \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"
- */
-class Talon : public PWMSpeedController {
- public:
-  /**
-   * Constructor for a Talon (original or Talon SR).
-   *
-   * @param channel The PWM channel number that the Talon is attached to. 0-9
-   *                are on-board, 10-19 are on the MXP port
-   */
-  explicit Talon(int channel);
-
-  Talon(Talon&&) = default;
-  Talon& operator=(Talon&&) = default;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Threads.h b/wpilibc/src/main/native/include/frc/Threads.h
index 3c44961..5822670 100644
--- a/wpilibc/src/main/native/include/frc/Threads.h
+++ b/wpilibc/src/main/native/include/frc/Threads.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -15,43 +12,45 @@
  * Get the thread priority for the specified thread.
  *
  * @param thread     Reference to the thread to get the priority for.
- * @param isRealTime Set to true if thread is realtime, otherwise false.
- * @return The current thread priority. Scaled 1-99, with 1 being highest.
+ * @param isRealTime Set to true if thread is real-time, otherwise false.
+ * @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.
  */
 int GetThreadPriority(std::thread& thread, bool* isRealTime);
 
 /**
- * Get the thread priority for the current thread
+ * Get the thread priority for the current thread.
  *
- * @param isRealTime Set to true if thread is realtime, otherwise false.
- * @return The current thread priority. Scaled 1-99.
+ * @param isRealTime Set to true if thread is real-time, otherwise false.
+ * @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.
  */
 int GetCurrentThreadPriority(bool* isRealTime);
 
 /**
- * Sets the thread priority for the specified thread
+ * Sets the thread priority for the specified thread.
  *
  * @param thread   Reference to the thread to set the priority of.
- * @param realTime Set to true to set a realtime priority, false for standard
+ * @param realTime Set to true to set a real-time 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
+ * @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.
  */
 bool SetThreadPriority(std::thread& thread, bool realTime, int priority);
 
 /**
- * Sets the thread priority for the current thread
+ * Sets the thread priority for the current thread.
  *
- * @param realTime Set to true to set a realtime priority, false for standard
+ * @param realTime Set to true to set a real-time 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
+ * @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.
  */
 bool SetCurrentThreadPriority(bool realTime, int priority);
 
diff --git a/wpilibc/src/main/native/include/frc/TimedRobot.h b/wpilibc/src/main/native/include/frc/TimedRobot.h
index 9dbc3f2..cc64c03 100644
--- a/wpilibc/src/main/native/include/frc/TimedRobot.h
+++ b/wpilibc/src/main/native/include/frc/TimedRobot.h
@@ -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.
 
 #pragma once
 
 #include <functional>
+#include <utility>
 #include <vector>
 
 #include <hal/Types.h>
@@ -16,9 +14,8 @@
 #include <wpi/deprecated.h>
 #include <wpi/priority_queue.h>
 
-#include "frc/ErrorBase.h"
 #include "frc/IterativeRobotBase.h"
-#include "frc2/Timer.h"
+#include "frc/Timer.h"
 
 namespace frc {
 
@@ -31,9 +28,9 @@
  * Periodic() functions from the base class are called on an interval by a
  * Notifier instance.
  */
-class TimedRobot : public IterativeRobotBase, public ErrorBase {
+class TimedRobot : public IterativeRobotBase {
  public:
-  static constexpr units::second_t kDefaultPeriod = 20_ms;
+  static constexpr auto kDefaultPeriod = 20_ms;
 
   /**
    * Provide an alternate "main loop" via StartCompetition().
@@ -46,11 +43,6 @@
   void EndCompetition() override;
 
   /**
-   * Get the time period between calls to Periodic() functions.
-   */
-  units::second_t GetPeriod() const;
-
-  /**
    * Constructor for TimedRobot.
    *
    * @deprecated use unit safe constructor instead.
@@ -105,14 +97,13 @@
      */
     Callback(std::function<void()> func, units::second_t startTime,
              units::second_t period, units::second_t offset)
-        : func{func},
+        : func{std::move(func)},
           period{period},
-          expirationTime{
-              startTime + offset +
-              units::math::floor((frc2::Timer::GetFPGATimestamp() - startTime) /
-                                 period) *
-                  period +
-              period} {}
+          expirationTime{startTime + offset +
+                         units::math::floor(
+                             (Timer::GetFPGATimestamp() - startTime) / period) *
+                             period +
+                         period} {}
 
     bool operator>(const Callback& rhs) const {
       return expirationTime > rhs.expirationTime;
diff --git a/wpilibc/src/main/native/include/frc/Timer.h b/wpilibc/src/main/native/include/frc/Timer.h
index ac166c5..0aed658 100644
--- a/wpilibc/src/main/native/include/frc/Timer.h
+++ b/wpilibc/src/main/native/include/frc/Timer.h
@@ -1,13 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include "frc2/Timer.h"
+#include <units/time.h>
+#include <wpi/deprecated.h>
 
 namespace frc {
 
@@ -21,23 +19,20 @@
  *
  * @param seconds Length of time to pause, in seconds.
  */
-void Wait(double seconds);
+void Wait(units::second_t seconds);
 
 /**
  * @brief  Gives real-time clock system time with nanosecond resolution
  * @return The time, just in case you want the robot to start autonomous at 8pm
  *         on Saturday.
  */
-double GetTime();
+units::second_t GetTime();
 
 /**
- * Timer objects measure accumulated time in seconds.
+ * A timer class.
  *
- * The timer object functions like a stopwatch. It can be started, stopped, and
- * cleared. When the timer is running its value counts up in seconds. When
- * stopped, the timer holds the current value. The implementation simply records
- * the time when started and subtracts the current time whenever the value is
- * requested.
+ * Note that if the user calls frc::sim::RestartTiming(), they should also reset
+ * the timer so Get() won't return a negative duration.
  */
 class Timer {
  public:
@@ -51,10 +46,10 @@
 
   virtual ~Timer() = default;
 
-  Timer(const Timer& rhs) = default;
-  Timer& operator=(const Timer& rhs) = default;
-  Timer(Timer&& rhs) = default;
-  Timer& operator=(Timer&& rhs) = default;
+  Timer(const Timer&) = default;
+  Timer& operator=(const Timer&) = default;
+  Timer(Timer&&) = default;
+  Timer& operator=(Timer&&) = default;
 
   /**
    * Get the current time from the timer. If the clock is running it is derived
@@ -63,7 +58,7 @@
    *
    * @return Current time value for this timer in seconds
    */
-  double Get() const;
+  units::second_t Get() const;
 
   /**
    * Reset the timer by setting the time to 0.
@@ -77,7 +72,8 @@
    * Start the timer running.
    *
    * Just set the running flag to true indicating that all time requests should
-   * be relative to the system clock.
+   * be relative to the system clock. Note that this method is a no-op if the
+   * timer is already running.
    */
   void Start();
 
@@ -91,14 +87,34 @@
   void Stop();
 
   /**
+   * Check if the period specified has passed.
+   *
+   * @param period The period to check.
+   * @return       True if the period has passed.
+   */
+  bool HasElapsed(units::second_t period) const;
+
+  /**
    * Check if the period specified has passed and if it has, advance the start
    * time by that period. This is useful to decide if it's time to do periodic
    * work without drifting later by the time it took to get around to checking.
    *
-   * @param period The period to check for (in seconds).
+   * @param period The period to check for.
+   * @return       True if the period has passed.
+   * @deprecated Use AdvanceIfElapsed() instead.
+   */
+  WPI_DEPRECATED("Use AdvanceIfElapsed() instead.")
+  bool HasPeriodPassed(units::second_t period);
+
+  /**
+   * Check if the period specified has passed and if it has, advance the start
+   * time by that period. This is useful to decide if it's time to do periodic
+   * work without drifting later by the time it took to get around to checking.
+   *
+   * @param period The period to check for.
    * @return       True if the period has passed.
    */
-  bool HasPeriodPassed(double period);
+  bool AdvanceIfElapsed(units::second_t period);
 
   /**
    * Return the FPGA system clock time in seconds.
@@ -108,7 +124,7 @@
    *
    * @returns Robot running time in seconds.
    */
-  static double GetFPGATimestamp();
+  static units::second_t GetFPGATimestamp();
 
   /**
    * Return the approximate match time.
@@ -125,10 +141,12 @@
    *
    * @return Time remaining in current match period (auto or teleop)
    */
-  static double GetMatchTime();
+  static units::second_t GetMatchTime();
 
  private:
-  frc2::Timer m_timer;
+  units::second_t m_startTime = 0_s;
+  units::second_t m_accumulatedTime = 0_s;
+  bool m_running = false;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/TimesliceRobot.h b/wpilibc/src/main/native/include/frc/TimesliceRobot.h
new file mode 100644
index 0000000..bc045d5
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/TimesliceRobot.h
@@ -0,0 +1,120 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <functional>
+
+#include <units/time.h>
+
+#include "frc/TimedRobot.h"
+
+namespace frc {
+
+/**
+ * TimesliceRobot extends the TimedRobot robot program framework to provide
+ * timeslice scheduling of periodic functions.
+ *
+ * The TimesliceRobot class is intended to be subclassed by a user creating a
+ * robot program.
+ *
+ * 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.
+ *
+ * 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>
+ *
+ * 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.
+ *
+ * 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
+ * frc::SetCurrentThreadPriority(). An RT priority of 15 is a reasonable choice.
+ *
+ * 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.
+ */
+class TimesliceRobot : public TimedRobot {
+ public:
+  /**
+   * Constructor for TimesliceRobot.
+   *
+   * @param robotPeriodicAllocation The allocation to give the TimesliceRobot
+   *                                periodic functions.
+   * @param controllerPeriod The controller period. The sum of all scheduler
+   *                         allocations should be less than or equal to this
+   *                         value.
+   */
+  explicit TimesliceRobot(units::second_t robotPeriodicAllocation,
+                          units::second_t 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.
+   *
+   * 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 out of the controller
+   *                   period.
+   */
+  void Schedule(std::function<void()> func, units::second_t allocation);
+
+ private:
+  units::second_t m_nextOffset;
+  units::second_t m_controllerPeriod;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/Tracer.h b/wpilibc/src/main/native/include/frc/Tracer.h
index 627b07b..2acb017 100644
--- a/wpilibc/src/main/native/include/frc/Tracer.h
+++ b/wpilibc/src/main/native/include/frc/Tracer.h
@@ -1,17 +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.
 
 #pragma once
 
 #include <chrono>
+#include <string_view>
 
 #include <hal/cpp/fpga_clock.h>
 #include <wpi/StringMap.h>
-#include <wpi/StringRef.h>
 
 namespace wpi {
 class raw_ostream;
@@ -51,7 +48,7 @@
    *
    * @param epochName The name to associate with the epoch.
    */
-  void AddEpoch(wpi::StringRef epochName);
+  void AddEpoch(std::string_view epochName);
 
   /**
    * Prints list of epochs added so far and their times to the DriverStation.
diff --git a/wpilibc/src/main/native/include/frc/Ultrasonic.h b/wpilibc/src/main/native/include/frc/Ultrasonic.h
index f6d301b..253192f 100644
--- a/wpilibc/src/main/native/include/frc/Ultrasonic.h
+++ b/wpilibc/src/main/native/include/frc/Ultrasonic.h
@@ -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.
 
 #pragma once
 
@@ -13,12 +10,13 @@
 #include <vector>
 
 #include <hal/SimDevice.h>
+#include <units/length.h>
+#include <units/time.h>
+#include <units/velocity.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/Counter.h"
-#include "frc/ErrorBase.h"
-#include "frc/PIDSource.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
@@ -37,13 +35,9 @@
  * received. The time that the line is high determines the round trip distance
  * (time of flight).
  */
-class Ultrasonic : public ErrorBase,
-                   public Sendable,
-                   public PIDSource,
-                   public SendableHelper<Ultrasonic> {
+class Ultrasonic : public wpi::Sendable,
+                   public wpi::SendableHelper<Ultrasonic> {
  public:
-  enum DistanceUnit { kInches = 0, kMilliMeters = 1 };
-
   /**
    * Create an instance of the Ultrasonic Sensor.
    *
@@ -54,9 +48,8 @@
    * @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
    */
-  Ultrasonic(int pingChannel, int echoChannel, DistanceUnit units = kInches);
+  Ultrasonic(int pingChannel, int echoChannel);
 
   /**
    * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo
@@ -66,10 +59,8 @@
    *                    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
    */
-  Ultrasonic(DigitalOutput* pingChannel, DigitalInput* echoChannel,
-             DistanceUnit units = kInches);
+  Ultrasonic(DigitalOutput* pingChannel, DigitalInput* echoChannel);
 
   /**
    * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo
@@ -79,10 +70,8 @@
    *                    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
    */
-  Ultrasonic(DigitalOutput& pingChannel, DigitalInput& echoChannel,
-             DistanceUnit units = kInches);
+  Ultrasonic(DigitalOutput& pingChannel, DigitalInput& echoChannel);
 
   /**
    * Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo
@@ -92,17 +81,17 @@
    *                    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
    */
   Ultrasonic(std::shared_ptr<DigitalOutput> pingChannel,
-             std::shared_ptr<DigitalInput> echoChannel,
-             DistanceUnit units = kInches);
+             std::shared_ptr<DigitalInput> echoChannel);
 
   ~Ultrasonic() override;
 
   Ultrasonic(Ultrasonic&&) = default;
   Ultrasonic& operator=(Ultrasonic&&) = default;
 
+  int GetEchoChannel() const;
+
   /**
    * Single ping to ultrasonic sensor.
    *
@@ -138,52 +127,19 @@
   static void SetAutomaticMode(bool enabling);
 
   /**
-   * Get the range in inches from the ultrasonic sensor.
+   * Get the range from the ultrasonic sensor.
    *
-   * @return Range in inches of the target returned from the ultrasonic sensor.
-   *         If there is no valid value yet, i.e. at least one measurement
-   *         hasn't completed, then return 0.
+   * @return Range of the target returned from the ultrasonic sensor. If there
+   *         is no valid value yet, i.e. at least one measurement hasn't
+   *         completed, then return 0.
    */
-  double GetRangeInches() const;
-
-  /**
-   * Get the range in millimeters from the ultrasonic sensor.
-   *
-   * @return Range in millimeters of the target returned by the ultrasonic
-   *         sensor. If there is no valid value yet, i.e. at least one
-   *         measurement hasn't completed, then return 0.
-   */
-  double GetRangeMM() const;
+  units::meter_t GetRange() const;
 
   bool IsEnabled() const;
 
   void SetEnabled(bool enable);
 
-  /**
-   * Set the current DistanceUnit that should be used for the PIDSource base
-   * object.
-   *
-   * @param units The DistanceUnit that should be used.
-   */
-  void SetDistanceUnits(DistanceUnit units);
-
-  /**
-   * Get the current DistanceUnit that is used for the PIDSource base object.
-   *
-   * @return The type of DistanceUnit that is being used.
-   */
-  DistanceUnit GetDistanceUnits() const;
-
-  /**
-   * Get the range in the current DistanceUnit for the PIDSource base object.
-   *
-   * @return The range in DistanceUnit
-   */
-  double PIDGet() override;
-
-  void SetPIDSourceType(PIDSourceType pidSource) override;
-
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   /**
@@ -215,8 +171,8 @@
   static constexpr int kPriority = 64;
 
   // Max time (ms) between readings.
-  static constexpr double kMaxUltrasonicTime = 0.1;
-  static constexpr double kSpeedOfSoundInchesPerSec = 1130.0 * 12.0;
+  static constexpr auto kMaxUltrasonicTime = 0.1_s;
+  static constexpr auto kSpeedOfSound = 1130_fps;
 
   // Thread doing the round-robin automatic sensing
   static std::thread m_thread;
@@ -231,7 +187,6 @@
   std::shared_ptr<DigitalInput> m_echoChannel;
   bool m_enabled = false;
   Counter m_counter;
-  DistanceUnit m_units;
 
   hal::SimDevice m_simDevice;
   hal::SimBoolean m_simRangeValid;
diff --git a/wpilibc/src/main/native/include/frc/Utility.h b/wpilibc/src/main/native/include/frc/Utility.h
deleted file mode 100644
index a02e583..0000000
--- a/wpilibc/src/main/native/include/frc/Utility.h
+++ /dev/null
@@ -1,68 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-/**
- * @file Contains global utility functions
- */
-
-#include <wpi/StringRef.h>
-#include <wpi/Twine.h>
-
-#define wpi_assert(condition) \
-  wpi_assert_impl(condition, #condition, "", __FILE__, __LINE__, __FUNCTION__)
-#define wpi_assertWithMessage(condition, message)                     \
-  wpi_assert_impl(condition, #condition, message, __FILE__, __LINE__, \
-                  __FUNCTION__)
-
-#define wpi_assertEqual(a, b) \
-  wpi_assertEqual_impl(a, b, #a, #b, "", __FILE__, __LINE__, __FUNCTION__)
-#define wpi_assertEqualWithMessage(a, b, message) \
-  wpi_assertEqual_impl(a, b, #a, #b, message, __FILE__, __LINE__, __FUNCTION__)
-
-#define wpi_assertNotEqual(a, b) \
-  wpi_assertNotEqual_impl(a, b, #a, #b, "", __FILE__, __LINE__, __FUNCTION__)
-#define wpi_assertNotEqualWithMessage(a, b, message)                 \
-  wpi_assertNotEqual_impl(a, b, #a, #b, message, __FILE__, __LINE__, \
-                          __FUNCTION__)
-
-/**
- * Assert implementation.
- *
- * This allows breakpoints to be set on an assert. The users don't call this,
- * but instead use the wpi_assert macros in Utility.h.
- */
-bool wpi_assert_impl(bool conditionValue, const wpi::Twine& conditionText,
-                     const wpi::Twine& message, wpi::StringRef fileName,
-                     int lineNumber, wpi::StringRef funcName);
-
-/**
- * Assert equal implementation.
- *
- * This determines whether the two given integers are equal. If not, the value
- * of each is printed along with an optional message string. The users don't
- * call this, but instead use the wpi_assertEqual macros in Utility.h.
- */
-bool wpi_assertEqual_impl(int valueA, int valueB,
-                          const wpi::Twine& valueAString,
-                          const wpi::Twine& valueBString,
-                          const wpi::Twine& message, wpi::StringRef fileName,
-                          int lineNumber, wpi::StringRef funcName);
-
-/**
- * Assert not equal implementation.
- *
- * This determines whether the two given integers are equal. If so, the value of
- * each is printed along with an optional message string. The users don't call
- * this, but instead use the wpi_assertNotEqual macros in Utility.h.
- */
-bool wpi_assertNotEqual_impl(int valueA, int valueB,
-                             const wpi::Twine& valueAString,
-                             const wpi::Twine& valueBString,
-                             const wpi::Twine& message, wpi::StringRef fileName,
-                             int lineNumber, wpi::StringRef funcName);
diff --git a/wpilibc/src/main/native/include/frc/Victor.h b/wpilibc/src/main/native/include/frc/Victor.h
deleted file mode 100644
index 89c4a89..0000000
--- a/wpilibc/src/main/native/include/frc/Victor.h
+++ /dev/null
@@ -1,48 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/PWMSpeedController.h"
-
-namespace frc {
-
-/**
- * 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.
- *
- * 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 as well 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.
- *
- * \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"
- */
-class Victor : public PWMSpeedController {
- public:
-  /**
-   * Constructor for a Victor.
-   *
-   * @param channel The PWM channel number that the Victor is attached to. 0-9
-   *                are on-board, 10-19 are on the MXP port
-   */
-  explicit Victor(int channel);
-
-  Victor(Victor&&) = default;
-  Victor& operator=(Victor&&) = default;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/VictorSP.h b/wpilibc/src/main/native/include/frc/VictorSP.h
deleted file mode 100644
index d8aa8e8..0000000
--- a/wpilibc/src/main/native/include/frc/VictorSP.h
+++ /dev/null
@@ -1,44 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/PWMSpeedController.h"
-
-namespace frc {
-
-/**
- * Vex Robotics Victor SP Speed Controller.
- *
- * Note that the Victor SP 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 SP User
- * Manual available from Vex.
- *
- * \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"
- */
-class VictorSP : public PWMSpeedController {
- public:
-  /**
-   * Constructor for a Victor SP.
-   *
-   * @param channel The PWM channel that the VictorSP is attached to. 0-9 are
-   *                on-board, 10-19 are on the MXP port
-   */
-  explicit VictorSP(int channel);
-
-  VictorSP(VictorSP&&) = default;
-  VictorSP& operator=(VictorSP&&) = default;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/WPIErrors.h b/wpilibc/src/main/native/include/frc/WPIErrors.h
deleted file mode 100644
index 8325c92..0000000
--- a/wpilibc/src/main/native/include/frc/WPIErrors.h
+++ /dev/null
@@ -1,95 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <stdint.h>
-
-#define S(label, offset, message)                                        \
-  constexpr inline const char* wpi_error_s_##label() { return message; } \
-  constexpr inline int wpi_error_value_##label() { return offset; }
-
-// Fatal errors
-S(ModuleIndexOutOfRange, -1,
-  "Allocating module that is out of range or not found")
-S(ChannelIndexOutOfRange, -1, "Allocating channel that is out of range")
-S(NotAllocated, -2, "Attempting to free unallocated resource")
-S(ResourceAlreadyAllocated, -3, "Attempted to reuse an allocated resource")
-S(NoAvailableResources, -4, "No available resources to allocate")
-S(NullParameter, -5, "A pointer parameter to a method is nullptr")
-S(Timeout, -6, "A timeout has been exceeded")
-S(CompassManufacturerError, -7, "Compass manufacturer doesn't match HiTechnic")
-S(CompassTypeError, -8,
-  "Compass type doesn't match expected type for HiTechnic compass")
-S(IncompatibleMode, -9, "The object is in an incompatible mode")
-S(AnalogTriggerLimitOrderError, -10,
-  "AnalogTrigger limits error.  Lower limit > Upper Limit")
-S(AnalogTriggerPulseOutputError, -11,
-  "Attempted to read AnalogTrigger pulse output.")
-S(TaskError, -12, "Task can't be started")
-S(TaskIDError, -13, "Task error: Invalid ID.")
-S(TaskDeletedError, -14, "Task error: Task already deleted.")
-S(TaskOptionsError, -15, "Task error: Invalid options.")
-S(TaskMemoryError, -16, "Task can't be started due to insufficient memory.")
-S(TaskPriorityError, -17, "Task error: Invalid priority [1-255].")
-S(DriveUninitialized, -18, "RobotDrive not initialized for the C interface")
-S(CompressorNonMatching, -19,
-  "Compressor slot/channel doesn't match previous instance")
-S(CompressorAlreadyDefined, -20, "Creating a second compressor instance")
-S(CompressorUndefined, -21,
-  "Using compressor functions without defining compressor")
-S(InconsistentArrayValueAdded, -22,
-  "When packing data into an array to the dashboard, not all values added were "
-  "of the same type.")
-S(MismatchedComplexTypeClose, -23,
-  "When packing data to the dashboard, a Close for a complex type was called "
-  "without a matching Open.")
-S(DashboardDataOverflow, -24,
-  "When packing data to the dashboard, too much data was packed and the buffer "
-  "overflowed.")
-S(DashboardDataCollision, -25,
-  "The same buffer was used for packing data and for printing.")
-S(EnhancedIOMissing, -26, "IO is not attached or Enhanced IO is not enabled.")
-S(LineNotOutput, -27,
-  "Cannot SetDigitalOutput for a line not configured for output.")
-S(ParameterOutOfRange, -28, "A parameter is out of range.")
-S(SPIClockRateTooLow, -29, "SPI clock rate was below the minimum supported")
-S(JaguarVersionError, -30, "Jaguar firmware version error")
-S(JaguarMessageNotFound, -31, "Jaguar message not found")
-S(NetworkTablesReadError, -40, "Error reading NetworkTables socket")
-S(NetworkTablesBufferFull, -41, "Buffer full writing to NetworkTables socket")
-S(NetworkTablesWrongType, -42,
-  "The wrong type was read from the NetworkTables entry")
-S(NetworkTablesCorrupt, -43, "NetworkTables data stream is corrupt")
-S(SmartDashboardMissingKey, -43, "SmartDashboard data does not exist")
-S(CommandIllegalUse, -50, "Illegal use of Command")
-S(UnsupportedInSimulation, -80, "Unsupported in simulation")
-S(CameraServerError, -90, "CameraServer error")
-S(InvalidParameter, -100, "Invalid parameter value")
-
-// Warnings
-S(SampleRateTooHigh, 1, "Analog module sample rate is too high")
-S(VoltageOutOfRange, 2,
-  "Voltage to convert to raw value is out of range [-10; 10]")
-S(CompressorTaskError, 3, "Compressor task won't start")
-S(LoopTimingError, 4, "Digital module loop timing is not the expected value")
-S(NonBinaryDigitalValue, 5, "Digital output value is not 0 or 1")
-S(IncorrectBatteryChannel, 6,
-  "Battery measurement channel is not correct value")
-S(BadJoystickIndex, 7, "Joystick index is out of range, should be 0-3")
-S(BadJoystickAxis, 8, "Joystick axis or POV is out of range")
-S(InvalidMotorIndex, 9, "Motor index is out of range, should be 0-3")
-S(DriverStationTaskError, 10, "Driver Station task won't start")
-S(EnhancedIOPWMPeriodOutOfRange, 11,
-  "Driver Station Enhanced IO PWM Output period out of range.")
-S(SPIWriteNoMOSI, 12, "Cannot write to SPI port with no MOSI output")
-S(SPIReadNoMISO, 13, "Cannot read from SPI port with no MISO input")
-S(SPIReadNoData, 14, "No data available to read from SPI")
-S(IncompatibleState, 15,
-  "Incompatible State: The operation cannot be completed")
-
-#undef S
diff --git a/wpilibc/src/main/native/include/frc/WPIErrors.mac b/wpilibc/src/main/native/include/frc/WPIErrors.mac
new file mode 100644
index 0000000..c6c96e9
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/WPIErrors.mac
@@ -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.
+
+S(ModuleIndexOutOfRange, -1,
+  "Allocating module that is out of range or not found")
+S(ChannelIndexOutOfRange, -45, "Allocating channel that is out of range")
+S(NotAllocated, -2, "Attempting to free unallocated resource")
+S(ResourceAlreadyAllocated, -3, "Attempted to reuse an allocated resource")
+S(NoAvailableResources, -4, "No available resources to allocate")
+S(NullParameter, -5, "A pointer parameter to a method is nullptr")
+S(Timeout, -6, "A timeout has been exceeded")
+S(CompassManufacturerError, -7, "Compass manufacturer doesn't match HiTechnic")
+S(CompassTypeError, -8,
+  "Compass type doesn't match expected type for HiTechnic compass")
+S(IncompatibleMode, -9, "The object is in an incompatible mode")
+S(AnalogTriggerLimitOrderError, -10,
+  "AnalogTrigger limits error.  Lower limit > Upper Limit")
+S(AnalogTriggerPulseOutputError, -11,
+  "Attempted to read AnalogTrigger pulse output")
+S(TaskError, -12, "Task can't be started")
+S(TaskIDError, -13, "Task error: Invalid ID")
+S(TaskDeletedError, -14, "Task error: Task already deleted")
+S(TaskOptionsError, -15, "Task error: Invalid options")
+S(TaskMemoryError, -16, "Task can't be started due to insufficient memory")
+S(TaskPriorityError, -17, "Task error: Invalid priority [1-255]")
+S(DriveUninitialized, -18, "RobotDrive not initialized for the C interface")
+S(CompressorNonMatching, -19,
+  "Compressor slot/channel doesn't match previous instance")
+S(CompressorAlreadyDefined, -20, "Creating a second compressor instance")
+S(CompressorUndefined, -21,
+  "Using compressor functions without defining compressor")
+S(InconsistentArrayValueAdded, -22,
+  "When packing data into an array to the dashboard, not all values added were "
+  "of the same type")
+S(MismatchedComplexTypeClose, -23,
+  "When packing data to the dashboard, a Close for a complex type was called "
+  "without a matching Open")
+S(DashboardDataOverflow, -24,
+  "When packing data to the dashboard, too much data was packed and the buffer "
+  "overflowed")
+S(DashboardDataCollision, -25,
+  "The same buffer was used for packing data and for printing")
+S(EnhancedIOMissing, -26, "IO is not attached or Enhanced IO is not enabled")
+S(LineNotOutput, -27,
+  "Cannot SetDigitalOutput for a line not configured for output")
+S(ParameterOutOfRange, -28, "A parameter is out of range")
+S(SPIClockRateTooLow, -29, "SPI clock rate was below the minimum supported")
+S(JaguarVersionError, -30, "Jaguar firmware version error")
+S(JaguarMessageNotFound, -31, "Jaguar message not found")
+S(NetworkTablesReadError, -40, "Error reading NetworkTables socket")
+S(NetworkTablesBufferFull, -41, "Buffer full writing to NetworkTables socket")
+S(NetworkTablesWrongType, -42,
+  "The wrong type was read from the NetworkTables entry")
+S(NetworkTablesCorrupt, -43, "NetworkTables data stream is corrupt")
+S(SmartDashboardMissingKey, -44, "SmartDashboard data does not exist")
+S(CommandIllegalUse, -50, "Illegal use of Command")
+S(UnsupportedInSimulation, -80, "Unsupported in simulation")
+S(CameraServerError, -90, "CameraServer error")
+S(InvalidParameter, -100, "Invalid parameter value")
+S(AssertionFailure, -110, "Assertion failed")
+S(Error, -111, "Error")
diff --git a/wpilibc/src/main/native/include/frc/WPILib.h b/wpilibc/src/main/native/include/frc/WPILib.h
deleted file mode 100644
index 634d0f5..0000000
--- a/wpilibc/src/main/native/include/frc/WPILib.h
+++ /dev/null
@@ -1,110 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-// clang-format off
-#ifdef _MSC_VER
-#pragma message("warning: Including this header drastically increases compilation times and is bad style. Include only what you use instead.")
-#else
-#warning "Including this header drastically increases compilation times and is bad style. Include only what you use instead."
-#endif
-
-// clang-format on
-
-#if __has_include(<cameraserver/CameraServer.h>)
-#include <cameraserver/CameraServer.h>
-#include <vision/VisionRunner.h>
-#endif
-
-#include "frc/ADXL345_I2C.h"
-#include "frc/ADXL345_SPI.h"
-#include "frc/ADXL362.h"
-#include "frc/ADXRS450_Gyro.h"
-#include "frc/AnalogAccelerometer.h"
-#include "frc/AnalogGyro.h"
-#include "frc/AnalogInput.h"
-#include "frc/AnalogOutput.h"
-#include "frc/AnalogPotentiometer.h"
-#include "frc/AnalogTrigger.h"
-#include "frc/AnalogTriggerOutput.h"
-#include "frc/BuiltInAccelerometer.h"
-#include "frc/Compressor.h"
-#include "frc/Counter.h"
-#include "frc/DMC60.h"
-#include "frc/DigitalInput.h"
-#include "frc/DigitalOutput.h"
-#include "frc/DigitalSource.h"
-#include "frc/DoubleSolenoid.h"
-#include "frc/DriverStation.h"
-#include "frc/Encoder.h"
-#include "frc/ErrorBase.h"
-#include "frc/GearTooth.h"
-#include "frc/GenericHID.h"
-#include "frc/I2C.h"
-#include "frc/InterruptableSensorBase.h"
-#include "frc/IterativeRobot.h"
-#include "frc/Jaguar.h"
-#include "frc/Joystick.h"
-#include "frc/NidecBrushless.h"
-#include "frc/Notifier.h"
-#include "frc/PIDController.h"
-#include "frc/PIDOutput.h"
-#include "frc/PIDSource.h"
-#include "frc/PWM.h"
-#include "frc/PWMSpeedController.h"
-#include "frc/PWMTalonSRX.h"
-#include "frc/PWMVictorSPX.h"
-#include "frc/PowerDistributionPanel.h"
-#include "frc/Preferences.h"
-#include "frc/Relay.h"
-#include "frc/RobotBase.h"
-#include "frc/RobotController.h"
-#include "frc/RobotDrive.h"
-#include "frc/SD540.h"
-#include "frc/SPI.h"
-#include "frc/SensorUtil.h"
-#include "frc/SerialPort.h"
-#include "frc/Servo.h"
-#include "frc/Solenoid.h"
-#include "frc/Spark.h"
-#include "frc/SpeedController.h"
-#include "frc/SpeedControllerGroup.h"
-#include "frc/Talon.h"
-#include "frc/Threads.h"
-#include "frc/TimedRobot.h"
-#include "frc/Timer.h"
-#include "frc/Ultrasonic.h"
-#include "frc/Utility.h"
-#include "frc/Victor.h"
-#include "frc/VictorSP.h"
-#include "frc/WPIErrors.h"
-#include "frc/XboxController.h"
-#if __has_include("frc/buttons/InternalButton.h")
-#include "frc/buttons/InternalButton.h"
-#include "frc/buttons/JoystickButton.h"
-#include "frc/buttons/NetworkButton.h"
-#include "frc/commands/Command.h"
-#include "frc/commands/CommandGroup.h"
-#include "frc/commands/PIDCommand.h"
-#include "frc/commands/PIDSubsystem.h"
-#include "frc/commands/PrintCommand.h"
-#include "frc/commands/StartCommand.h"
-#include "frc/commands/Subsystem.h"
-#include "frc/commands/WaitCommand.h"
-#include "frc/commands/WaitForChildren.h"
-#include "frc/commands/WaitUntilCommand.h"
-#endif
-#include "frc/drive/DifferentialDrive.h"
-#include "frc/drive/KilloughDrive.h"
-#include "frc/drive/MecanumDrive.h"
-#include "frc/filters/LinearDigitalFilter.h"
-#include "frc/interfaces/Accelerometer.h"
-#include "frc/interfaces/Gyro.h"
-#include "frc/interfaces/Potentiometer.h"
-#include "frc/smartdashboard/SendableChooser.h"
-#include "frc/smartdashboard/SmartDashboard.h"
diff --git a/wpilibc/src/main/native/include/frc/WPIWarnings.mac b/wpilibc/src/main/native/include/frc/WPIWarnings.mac
new file mode 100644
index 0000000..fa63494
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/WPIWarnings.mac
@@ -0,0 +1,24 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+S(SampleRateTooHigh, 1, "Analog module sample rate is too high")
+S(VoltageOutOfRange, 2,
+  "Voltage to convert to raw value is out of range [-10; 10]")
+S(CompressorTaskError, 3, "Compressor task won't start")
+S(LoopTimingError, 4, "Digital module loop timing is not the expected value")
+S(NonBinaryDigitalValue, 5, "Digital output value is not 0 or 1")
+S(IncorrectBatteryChannel, 6,
+  "Battery measurement channel is not correct value")
+S(BadJoystickIndex, 7, "Joystick index is out of range, should be 0-3")
+S(BadJoystickAxis, 8, "Joystick axis or POV is out of range")
+S(InvalidMotorIndex, 9, "Motor index is out of range, should be 0-3")
+S(DriverStationTaskError, 10, "Driver Station task won't start")
+S(EnhancedIOPWMPeriodOutOfRange, 11,
+  "Driver Station Enhanced IO PWM Output period out of range")
+S(SPIWriteNoMOSI, 12, "Cannot write to SPI port with no MOSI output")
+S(SPIReadNoMISO, 13, "Cannot read from SPI port with no MISO input")
+S(SPIReadNoData, 14, "No data available to read from SPI")
+S(IncompatibleState, 15,
+  "Incompatible State: The operation cannot be completed")
+S(Warning, 16, "Warning")
diff --git a/wpilibc/src/main/native/include/frc/Watchdog.h b/wpilibc/src/main/native/include/frc/Watchdog.h
index 6fc3793..d85674d 100644
--- a/wpilibc/src/main/native/include/frc/Watchdog.h
+++ b/wpilibc/src/main/native/include/frc/Watchdog.h
@@ -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.
 
 #pragma once
 
 #include <functional>
+#include <string_view>
 #include <utility>
 
 #include <units/time.h>
-#include <wpi/StringRef.h>
-#include <wpi/deprecated.h>
 
 #include "frc/Tracer.h"
 
@@ -32,19 +28,6 @@
   /**
    * Watchdog constructor.
    *
-   * @deprecated use unit-safe version instead.
-   * Watchdog(units::second_t timeout, std::function<void()> callback)
-   *
-   * @param timeout  The watchdog's timeout in seconds with microsecond
-   *                 resolution.
-   * @param callback This function is called when the timeout expires.
-   */
-  WPI_DEPRECATED("Use unit-safe version instead")
-  Watchdog(double timeout, std::function<void()> callback);
-
-  /**
-   * Watchdog constructor.
-   *
    * @param timeout  The watchdog's timeout in seconds with microsecond
    *                 resolution.
    * @param callback This function is called when the timeout expires.
@@ -52,11 +35,6 @@
   Watchdog(units::second_t timeout, std::function<void()> callback);
 
   template <typename Callable, typename Arg, typename... Args>
-  WPI_DEPRECATED("Use unit-safe version instead")
-  Watchdog(double timeout, Callable&& f, Arg&& arg, Args&&... args)
-      : Watchdog(units::second_t{timeout}, arg, args...) {}
-
-  template <typename Callable, typename Arg, typename... Args>
   Watchdog(units::second_t timeout, Callable&& f, Arg&& arg, Args&&... args)
       : Watchdog(timeout,
                  std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
@@ -68,21 +46,9 @@
   Watchdog& operator=(Watchdog&& rhs);
 
   /**
-   * Returns the time in seconds since the watchdog was last fed.
+   * Returns the time since the watchdog was last fed.
    */
-  double GetTime() const;
-
-  /**
-   * Sets the watchdog's timeout.
-   *
-   * @deprecated use the unit safe version instead.
-   * SetTimeout(units::second_t timeout)
-   *
-   * @param timeout The watchdog's timeout in seconds with microsecond
-   *                resolution.
-   */
-  WPI_DEPRECATED("Use unit-safe version instead")
-  void SetTimeout(double timeout);
+  units::second_t GetTime() const;
 
   /**
    * Sets the watchdog's timeout.
@@ -93,9 +59,9 @@
   void SetTimeout(units::second_t timeout);
 
   /**
-   * Returns the watchdog's timeout in seconds.
+   * Returns the watchdog's timeout.
    */
-  double GetTimeout() const;
+  units::second_t GetTimeout() const;
 
   /**
    * Returns true if the watchdog timer has expired.
@@ -110,7 +76,7 @@
    *
    * @param epochName The name to associate with the epoch.
    */
-  void AddEpoch(wpi::StringRef epochName);
+  void AddEpoch(std::string_view epochName);
 
   /**
    * Prints list of epochs added so far and their times.
@@ -146,7 +112,7 @@
 
  private:
   // Used for timeout print rate-limiting
-  static constexpr units::second_t kMinPrintPeriod = 1_s;
+  static constexpr auto kMinPrintPeriod = 1_s;
 
   units::second_t m_startTime = 0_s;
   units::second_t m_timeout;
diff --git a/wpilibc/src/main/native/include/frc/XboxController.h b/wpilibc/src/main/native/include/frc/XboxController.h
index ddf4dc2..cbdc7d7 100644
--- a/wpilibc/src/main/native/include/frc/XboxController.h
+++ b/wpilibc/src/main/native/include/frc/XboxController.h
@@ -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.
 
 #pragma once
 
@@ -32,78 +29,102 @@
    */
   explicit XboxController(int port);
 
-  virtual ~XboxController() = default;
+  ~XboxController() override = default;
 
   XboxController(XboxController&&) = default;
   XboxController& operator=(XboxController&&) = default;
 
   /**
-   * Get the X axis value of the controller.
-   *
-   * @param hand Side of controller whose value should be returned.
+   * Get the X axis value of left side of the controller.
    */
-  double GetX(JoystickHand hand) const override;
+  double GetLeftX() const;
 
   /**
-   * Get the Y axis value of the controller.
-   *
-   * @param hand Side of controller whose value should be returned.
+   * Get the X axis value of right side of the controller.
    */
-  double GetY(JoystickHand hand) const override;
+  double GetRightX() const;
 
   /**
-   * Get the trigger axis value of the controller.
-   *
-   * @param hand Side of controller whose value should be returned.
+   * Get the Y axis value of left side of the controller.
    */
-  double GetTriggerAxis(JoystickHand hand) const;
+  double GetLeftY() const;
 
   /**
-   * Read the value of the bumper button on the controller.
-   *
-   * @param hand Side of controller whose value should be returned.
+   * Get the Y axis value of right side of the controller.
    */
-  bool GetBumper(JoystickHand hand) const;
+  double GetRightY() const;
 
   /**
-   * Whether the bumper 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.
+   * 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].
    */
-  bool GetBumperPressed(JoystickHand hand);
+  double GetLeftTriggerAxis() const;
 
   /**
-   * 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.
+   * 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].
    */
-  bool GetBumperReleased(JoystickHand hand);
+  double GetRightTriggerAxis() const;
 
   /**
-   * 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.
+   * Read the value of the left bumper (LB) button on the controller.
    */
-  bool GetStickButton(JoystickHand hand) const;
+  bool GetLeftBumper() const;
 
   /**
-   * Whether the stick button 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.
+   * Read the value of the right bumper (RB) button on the controller.
    */
-  bool GetStickButtonPressed(JoystickHand hand);
+  bool GetRightBumper() const;
 
   /**
-   * Whether the stick button 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.
+   * Whether the left bumper (LB) was pressed since the last check.
    */
-  bool GetStickButtonReleased(JoystickHand hand);
+  bool GetLeftBumperPressed();
+
+  /**
+   * Whether the right bumper (RB) was pressed since the last check.
+   */
+  bool GetRightBumperPressed();
+
+  /**
+   * Whether the left bumper (LB) was released since the last check.
+   */
+  bool GetLeftBumperReleased();
+
+  /**
+   * Whether the right bumper (RB) was released since the last check.
+   */
+  bool GetRightBumperReleased();
+
+  /**
+   * Read the value of the left stick button (LSB) on the controller.
+   */
+  bool GetLeftStickButton() const;
+
+  /**
+   * Read the value of the right stick button (RSB) on the controller.
+   */
+  bool GetRightStickButton() const;
+
+  /**
+   * Whether the left stick button (LSB) was pressed since the last check.
+   */
+  bool GetLeftStickButtonPressed();
+
+  /**
+   * Whether the right stick button (RSB) was pressed since the last check.
+   */
+  bool GetRightStickButtonPressed();
+
+  /**
+   * Whether the left stick button (LSB) was released since the last check.
+   */
+  bool GetLeftStickButtonReleased();
+
+  /**
+   * Whether the right stick button (RSB) was released since the last check.
+   */
+  bool GetRightStickButtonReleased();
 
   /**
    * Read the value of the A button on the controller.
@@ -213,7 +234,6 @@
   /**
    * Read the value of the start button on the controller.
    *
-   * @param hand Side of controller whose value should be returned.
    * @return The state of the button.
    */
   bool GetStartButton() const;
@@ -232,26 +252,26 @@
    */
   bool GetStartButtonReleased();
 
-  enum class Button {
-    kBumperLeft = 5,
-    kBumperRight = 6,
-    kStickLeft = 9,
-    kStickRight = 10,
-    kA = 1,
-    kB = 2,
-    kX = 3,
-    kY = 4,
-    kBack = 7,
-    kStart = 8
+  struct Button {
+    static constexpr int kLeftBumper = 5;
+    static constexpr int kRightBumper = 6;
+    static constexpr int kLeftStick = 9;
+    static constexpr int kRightStick = 10;
+    static constexpr int kA = 1;
+    static constexpr int kB = 2;
+    static constexpr int kX = 3;
+    static constexpr int kY = 4;
+    static constexpr int kBack = 7;
+    static constexpr int kStart = 8;
   };
 
-  enum class Axis {
-    kLeftX = 0,
-    kRightX = 4,
-    kLeftY = 1,
-    kRightY = 5,
-    kLeftTrigger = 2,
-    kRightTrigger = 3
+  struct Axis {
+    static constexpr int kLeftX = 0;
+    static constexpr int kRightX = 4;
+    static constexpr int kLeftY = 1;
+    static constexpr int kRightY = 5;
+    static constexpr int kLeftTrigger = 2;
+    static constexpr int kRightTrigger = 3;
   };
 };
 
diff --git a/wpilibc/src/main/native/include/frc/controller/ControllerUtil.h b/wpilibc/src/main/native/include/frc/controller/ControllerUtil.h
deleted file mode 100644
index 7603fde..0000000
--- a/wpilibc/src/main/native/include/frc/controller/ControllerUtil.h
+++ /dev/null
@@ -1,42 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <cmath>
-#include <type_traits>
-
-#include <units/math.h>
-
-namespace frc {
-
-/**
- * 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.
- */
-template <typename T>
-T GetModulusError(T reference, T measurement, T minimumInput, T maximumInput) {
-  T error = reference - measurement;
-  T modulus = maximumInput - minimumInput;
-
-  // Wrap error above maximum input
-  int numMax = (error + maximumInput) / modulus;
-  error -= numMax * modulus;
-
-  // Wrap error below minimum input
-  int numMin = (error + minimumInput) / modulus;
-  error -= numMin * modulus;
-
-  return error;
-}
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/controller/HolonomicDriveController.h b/wpilibc/src/main/native/include/frc/controller/HolonomicDriveController.h
deleted file mode 100644
index 916e1a9..0000000
--- a/wpilibc/src/main/native/include/frc/controller/HolonomicDriveController.h
+++ /dev/null
@@ -1,112 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <units/angle.h>
-#include <units/velocity.h>
-
-#include "frc/controller/PIDController.h"
-#include "frc/controller/ProfiledPIDController.h"
-#include "frc/geometry/Pose2d.h"
-#include "frc/geometry/Rotation2d.h"
-#include "frc/kinematics/ChassisSpeeds.h"
-#include "frc/trajectory/Trajectory.h"
-
-namespace frc {
-/**
- * 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.
- *
- * 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.
- */
-class HolonomicDriveController {
- public:
-  /**
-   * 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.
-   */
-  HolonomicDriveController(
-      const frc2::PIDController& xController,
-      const frc2::PIDController& yController,
-      const ProfiledPIDController<units::radian>& thetaController);
-
-  /**
-   * Returns true if the pose error is within tolerance of the reference.
-   */
-  bool AtReference() const;
-
-  /**
-   * Sets the pose error which is considered tolerable for use with
-   * AtReference().
-   *
-   * @param poseTolerance Pose error which is tolerable.
-   */
-  void SetTolerance(const Pose2d& tolerance);
-
-  /**
-   * Returns the next output of the holonomic drive controller.
-   *
-   * 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 linearVelocityRef  The desired linear velocity.
-   * @param angleRef           The desired ending angle.
-   */
-  ChassisSpeeds Calculate(const Pose2d& currentPose, const Pose2d& poseRef,
-                          units::meters_per_second_t linearVelocityRef,
-                          const Rotation2d& angleRef);
-
-  /**
-   * Returns the next output of the holonomic drive controller.
-   *
-   * 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.
-   * @param angleRef     The desired ending angle.
-   */
-  ChassisSpeeds Calculate(const Pose2d& currentPose,
-                          const Trajectory::State& desiredState,
-                          const Rotation2d& angleRef);
-
-  /**
-   * Enables and disables the controller for troubleshooting purposes. When
-   * Calculate() is called on a disabled controller, only feedforward values
-   * are returned.
-   *
-   * @param enabled If the controller is enabled or not.
-   */
-  void SetEnabled(bool enabled);
-
- private:
-  Pose2d m_poseError;
-  Pose2d m_poseTolerance;
-  bool m_enabled = true;
-
-  frc2::PIDController m_xController;
-  frc2::PIDController m_yController;
-  ProfiledPIDController<units::radian> m_thetaController;
-};
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/controller/PIDController.h b/wpilibc/src/main/native/include/frc/controller/PIDController.h
deleted file mode 100644
index 5f97c1e..0000000
--- a/wpilibc/src/main/native/include/frc/controller/PIDController.h
+++ /dev/null
@@ -1,243 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <functional>
-#include <limits>
-
-#include <units/time.h>
-
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
-
-namespace frc2 {
-
-/**
- * Implements a PID control loop.
- */
-class PIDController : public frc::Sendable,
-                      public frc::SendableHelper<PIDController> {
- public:
-  /**
-   * 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. The
-   *               default is 20 milliseconds.
-   */
-  PIDController(double Kp, double Ki, double Kd,
-                units::second_t period = 20_ms);
-
-  ~PIDController() override = default;
-
-  PIDController(const PIDController&) = default;
-  PIDController& operator=(const PIDController&) = default;
-  PIDController(PIDController&&) = default;
-  PIDController& operator=(PIDController&&) = default;
-
-  /**
-   * Sets the PID Controller gain parameters.
-   *
-   * Sets the proportional, integral, and differential coefficients.
-   *
-   * @param Kp Proportional coefficient
-   * @param Ki Integral coefficient
-   * @param Kd Differential coefficient
-   */
-  void SetPID(double Kp, double Ki, double Kd);
-
-  /**
-   * Sets the proportional coefficient of the PID controller gain.
-   *
-   * @param Kp proportional coefficient
-   */
-  void SetP(double Kp);
-
-  /**
-   * Sets the integral coefficient of the PID controller gain.
-   *
-   * @param Ki integral coefficient
-   */
-  void SetI(double Ki);
-
-  /**
-   * Sets the differential coefficient of the PID controller gain.
-   *
-   * @param Kd differential coefficient
-   */
-  void SetD(double Kd);
-
-  /**
-   * Gets the proportional coefficient.
-   *
-   * @return proportional coefficient
-   */
-  double GetP() const;
-
-  /**
-   * Gets the integral coefficient.
-   *
-   * @return integral coefficient
-   */
-  double GetI() const;
-
-  /**
-   * Gets the differential coefficient.
-   *
-   * @return differential coefficient
-   */
-  double GetD() const;
-
-  /**
-   * Gets the period of this controller.
-   *
-   * @return The period of the controller.
-   */
-  units::second_t GetPeriod() const;
-
-  /**
-   * Sets the setpoint for the PIDController.
-   *
-   * @param setpoint The desired setpoint.
-   */
-  void SetSetpoint(double setpoint);
-
-  /**
-   * Returns the current setpoint of the PIDController.
-   *
-   * @return The current setpoint.
-   */
-  double GetSetpoint() const;
-
-  /**
-   * Returns true if the error is within the tolerance of the setpoint.
-   *
-   * This will return false until at least one input value has been computed.
-   */
-  bool AtSetpoint() const;
-
-  /**
-   * Enables continuous input.
-   *
-   * 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.
-   */
-  void EnableContinuousInput(double minimumInput, double maximumInput);
-
-  /**
-   * Disables continuous input.
-   */
-  void DisableContinuousInput();
-
-  /**
-   * Returns true if continuous input is enabled.
-   */
-  bool IsContinuousInputEnabled() const;
-
-  /**
-   * Sets the minimum and maximum values for the integrator.
-   *
-   * 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.
-   */
-  void SetIntegratorRange(double minimumIntegral, double maximumIntegral);
-
-  /**
-   * Sets the error which is considered tolerable for use with AtSetpoint().
-   *
-   * @param positionTolerance Position error which is tolerable.
-   * @param velociytTolerance Velocity error which is tolerable.
-   */
-  void SetTolerance(
-      double positionTolerance,
-      double velocityTolerance = std::numeric_limits<double>::infinity());
-
-  /**
-   * Returns the difference between the setpoint and the measurement.
-   */
-  double GetPositionError() const;
-
-  /**
-   * Returns the velocity error.
-   */
-  double GetVelocityError() const;
-
-  /**
-   * Returns the next output of the PID controller.
-   *
-   * @param measurement The current measurement of the process variable.
-   */
-  double Calculate(double measurement);
-
-  /**
-   * 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.
-   */
-  double Calculate(double measurement, double setpoint);
-
-  /**
-   * Reset the previous error, the integral term, and disable the controller.
-   */
-  void Reset();
-
-  void InitSendable(frc::SendableBuilder& builder) override;
-
- private:
-  // Factor for "proportional" control
-  double m_Kp;
-
-  // Factor for "integral" control
-  double m_Ki;
-
-  // Factor for "derivative" control
-  double m_Kd;
-
-  // The period (in seconds) of the control loop running this controller
-  units::second_t m_period;
-
-  double m_maximumIntegral = 1.0;
-
-  double m_minimumIntegral = -1.0;
-
-  double m_maximumInput = 0;
-
-  double m_minimumInput = 0;
-
-  // Do the endpoints wrap around? eg. Absolute encoder
-  bool m_continuous = false;
-
-  // The error at the time of the most recent call to Calculate()
-  double m_positionError = 0;
-  double m_velocityError = 0;
-
-  // The error at the time of the second-most-recent call to Calculate() (used
-  // to compute velocity)
-  double m_prevError = 0;
-
-  // The sum of the errors for use in the integral calc
-  double m_totalError = 0;
-
-  // The error that is considered at setpoint.
-  double m_positionTolerance = 0.05;
-  double m_velocityTolerance = std::numeric_limits<double>::infinity();
-
-  double m_setpoint = 0;
-};
-
-}  // namespace frc2
diff --git a/wpilibc/src/main/native/include/frc/controller/ProfiledPIDController.h b/wpilibc/src/main/native/include/frc/controller/ProfiledPIDController.h
deleted file mode 100644
index fd246cd..0000000
--- a/wpilibc/src/main/native/include/frc/controller/ProfiledPIDController.h
+++ /dev/null
@@ -1,367 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <algorithm>
-#include <cmath>
-#include <functional>
-#include <limits>
-
-#include <units/time.h>
-
-#include "frc/controller/ControllerUtil.h"
-#include "frc/controller/PIDController.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableBuilder.h"
-#include "frc/smartdashboard/SendableHelper.h"
-#include "frc/trajectory/TrapezoidProfile.h"
-
-namespace frc {
-namespace detail {
-void ReportProfiledPIDController();
-}  // namespace detail
-
-/**
- * Implements a PID control loop whose setpoint is constrained by a trapezoid
- * profile.
- */
-template <class Distance>
-class ProfiledPIDController
-    : public Sendable,
-      public SendableHelper<ProfiledPIDController<Distance>> {
- public:
-  using Distance_t = units::unit_t<Distance>;
-  using Velocity =
-      units::compound_unit<Distance, units::inverse<units::seconds>>;
-  using Velocity_t = units::unit_t<Velocity>;
-  using Acceleration =
-      units::compound_unit<Velocity, units::inverse<units::seconds>>;
-  using Acceleration_t = units::unit_t<Acceleration>;
-  using State = typename TrapezoidProfile<Distance>::State;
-  using Constraints = typename TrapezoidProfile<Distance>::Constraints;
-
-  /**
-   * Allocates a ProfiledPIDController with the given constants for Kp, Ki, and
-   * Kd. Users should call reset() when they first start running the controller
-   * to avoid unwanted behavior.
-   *
-   * @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 20 milliseconds.
-   */
-  ProfiledPIDController(double Kp, double Ki, double Kd,
-                        Constraints constraints, units::second_t period = 20_ms)
-      : m_controller(Kp, Ki, Kd, period), m_constraints(constraints) {
-    detail::ReportProfiledPIDController();
-  }
-
-  ~ProfiledPIDController() override = default;
-
-  ProfiledPIDController(const ProfiledPIDController&) = default;
-  ProfiledPIDController& operator=(const ProfiledPIDController&) = default;
-  ProfiledPIDController(ProfiledPIDController&&) = default;
-  ProfiledPIDController& operator=(ProfiledPIDController&&) = default;
-
-  /**
-   * Sets the PID Controller gain parameters.
-   *
-   * Sets the proportional, integral, and differential coefficients.
-   *
-   * @param Kp Proportional coefficient
-   * @param Ki Integral coefficient
-   * @param Kd Differential coefficient
-   */
-  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
-   */
-  void SetP(double Kp) { m_controller.SetP(Kp); }
-
-  /**
-   * Sets the integral coefficient of the PID controller gain.
-   *
-   * @param Ki integral coefficient
-   */
-  void SetI(double Ki) { m_controller.SetI(Ki); }
-
-  /**
-   * Sets the differential coefficient of the PID controller gain.
-   *
-   * @param Kd differential coefficient
-   */
-  void SetD(double Kd) { m_controller.SetD(Kd); }
-
-  /**
-   * Gets the proportional coefficient.
-   *
-   * @return proportional coefficient
-   */
-  double GetP() const { return m_controller.GetP(); }
-
-  /**
-   * Gets the integral coefficient.
-   *
-   * @return integral coefficient
-   */
-  double GetI() const { return m_controller.GetI(); }
-
-  /**
-   * Gets the differential coefficient.
-   *
-   * @return differential coefficient
-   */
-  double GetD() const { return m_controller.GetD(); }
-
-  /**
-   * Gets the period of this controller.
-   *
-   * @return The period of the controller.
-   */
-  units::second_t GetPeriod() const { return m_controller.GetPeriod(); }
-
-  /**
-   * Sets the goal for the ProfiledPIDController.
-   *
-   * @param goal The desired unprofiled setpoint.
-   */
-  void SetGoal(State goal) { m_goal = goal; }
-
-  /**
-   * Sets the goal for the ProfiledPIDController.
-   *
-   * @param goal The desired unprofiled setpoint.
-   */
-  void SetGoal(Distance_t goal) { m_goal = {goal, Velocity_t(0)}; }
-
-  /**
-   * Gets the goal for the ProfiledPIDController.
-   */
-  State GetGoal() const { return m_goal; }
-
-  /**
-   * Returns true if the error is within the tolerance of the error.
-   *
-   * This will return false until at least one input value has been computed.
-   */
-  bool AtGoal() const { return AtSetpoint() && m_goal == m_setpoint; }
-
-  /**
-   * Set velocity and acceleration constraints for goal.
-   *
-   * @param constraints Velocity and acceleration constraints for goal.
-   */
-  void SetConstraints(Constraints constraints) { m_constraints = constraints; }
-
-  /**
-   * Returns the current setpoint of the ProfiledPIDController.
-   *
-   * @return The current setpoint.
-   */
-  State GetSetpoint() const { return m_setpoint; }
-
-  /**
-   * Returns true if the error is within the tolerance of the error.
-   *
-   * Currently this just reports on target as the actual value passes through
-   * the setpoint. Ideally it should be based on being within the tolerance for
-   * some period of time.
-   *
-   * This will return false until at least one input value has been computed.
-   */
-  bool AtSetpoint() const { return m_controller.AtSetpoint(); }
-
-  /**
-   * Enables continuous input.
-   *
-   * 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.
-   */
-  void EnableContinuousInput(Distance_t minimumInput, Distance_t maximumInput) {
-    m_controller.EnableContinuousInput(minimumInput.template to<double>(),
-                                       maximumInput.template to<double>());
-    m_minimumInput = minimumInput;
-    m_maximumInput = maximumInput;
-  }
-
-  /**
-   * Disables continuous input.
-   */
-  void DisableContinuousInput() { m_controller.DisableContinuousInput(); }
-
-  /**
-   * Sets the minimum and maximum values for the integrator.
-   *
-   * 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.
-   */
-  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.
-   * @param velocityTolerance Velocity error which is tolerable.
-   */
-  void SetTolerance(
-      Distance_t positionTolerance,
-      Velocity_t velocityTolerance = std::numeric_limits<double>::infinity()) {
-    m_controller.SetTolerance(positionTolerance.template to<double>(),
-                              velocityTolerance.template to<double>());
-  }
-
-  /**
-   * Returns the difference between the setpoint and the measurement.
-   *
-   * @return The error.
-   */
-  Distance_t GetPositionError() const {
-    return Distance_t(m_controller.GetPositionError());
-  }
-
-  /**
-   * Returns the change in error per second.
-   */
-  Velocity_t GetVelocityError() const {
-    return Velocity_t(m_controller.GetVelocityError());
-  }
-
-  /**
-   * Returns the next output of the PID controller.
-   *
-   * @param measurement The current measurement of the process variable.
-   */
-  double Calculate(Distance_t measurement) {
-    if (m_controller.IsContinuousInputEnabled()) {
-      // Get error which is smallest distance between goal and measurement
-      auto goalMinDistance = frc::GetModulusError<Distance_t>(
-          m_goal.position, measurement, m_minimumInput, m_maximumInput);
-      auto setpointMinDistance = frc::GetModulusError<Distance_t>(
-          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;
-    }
-
-    frc::TrapezoidProfile<Distance> profile{m_constraints, m_goal, m_setpoint};
-    m_setpoint = profile.Calculate(GetPeriod());
-    return m_controller.Calculate(measurement.template to<double>(),
-                                  m_setpoint.position.template to<double>());
-  }
-
-  /**
-   * 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.
-   */
-  double Calculate(Distance_t measurement, State 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.
-   */
-  double Calculate(Distance_t measurement, Distance_t 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.
-   */
-  double Calculate(
-      Distance_t measurement, Distance_t goal,
-      typename frc::TrapezoidProfile<Distance>::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.
-   */
-  void Reset(const 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.
-   */
-  void Reset(Distance_t measuredPosition, Velocity_t measuredVelocity) {
-    Reset(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.
-   */
-  void Reset(Distance_t measuredPosition) {
-    Reset(measuredPosition, Velocity_t(0));
-  }
-
-  void InitSendable(frc::SendableBuilder& builder) override {
-    builder.SetSmartDashboardType("ProfiledPIDController");
-    builder.AddDoubleProperty(
-        "p", [this] { return GetP(); }, [this](double value) { SetP(value); });
-    builder.AddDoubleProperty(
-        "i", [this] { return GetI(); }, [this](double value) { SetI(value); });
-    builder.AddDoubleProperty(
-        "d", [this] { return GetD(); }, [this](double value) { SetD(value); });
-    builder.AddDoubleProperty(
-        "goal", [this] { return GetGoal().position.template to<double>(); },
-        [this](double value) { SetGoal(Distance_t{value}); });
-  }
-
- private:
-  frc2::PIDController m_controller;
-  Distance_t m_minimumInput{0};
-  Distance_t m_maximumInput{0};
-  typename frc::TrapezoidProfile<Distance>::State m_goal;
-  typename frc::TrapezoidProfile<Distance>::State m_setpoint;
-  typename frc::TrapezoidProfile<Distance>::Constraints m_constraints;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/controller/RamseteController.h b/wpilibc/src/main/native/include/frc/controller/RamseteController.h
deleted file mode 100644
index e746bb3..0000000
--- a/wpilibc/src/main/native/include/frc/controller/RamseteController.h
+++ /dev/null
@@ -1,122 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <units/angular_velocity.h>
-#include <units/velocity.h>
-
-#include "frc/geometry/Pose2d.h"
-#include "frc/kinematics/ChassisSpeeds.h"
-#include "frc/trajectory/Trajectory.h"
-
-namespace frc {
-
-/**
- * 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.
- *
- * 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.
- *
- * 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").
- *
- * See <https://file.tavsys.net/control/controls-engineering-in-frc.pdf> section
- * on Ramsete unicycle controller for a derivation and analysis.
- */
-class RamseteController {
- public:
-  /**
-   * 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.
-   */
-  RamseteController(double b, double 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.
-   */
-  RamseteController() : RamseteController(2.0, 0.7) {}
-
-  /**
-   * Returns true if the pose error is within tolerance of the reference.
-   */
-  bool AtReference() const;
-
-  /**
-   * Sets the pose error which is considered tolerable for use with
-   * AtReference().
-   *
-   * @param poseTolerance Pose error which is tolerable.
-   */
-  void SetTolerance(const Pose2d& poseTolerance);
-
-  /**
-   * Returns the next output of the Ramsete controller.
-   *
-   * 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 linearVelocityRef  The desired linear velocity.
-   * @param angularVelocityRef The desired angular velocity.
-   */
-  ChassisSpeeds Calculate(const Pose2d& currentPose, const Pose2d& poseRef,
-                          units::meters_per_second_t linearVelocityRef,
-                          units::radians_per_second_t angularVelocityRef);
-
-  /**
-   * Returns the next output of the Ramsete controller.
-   *
-   * 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.
-   */
-  ChassisSpeeds Calculate(const Pose2d& currentPose,
-                          const Trajectory::State& desiredState);
-
-  /**
-   * Enables and disables the controller for troubleshooting purposes.
-   *
-   * @param enabled If the controller is enabled or not.
-   */
-  void SetEnabled(bool enabled);
-
- private:
-  double m_b;
-  double m_zeta;
-
-  Pose2d m_poseError;
-  Pose2d m_poseTolerance;
-  bool m_enabled = true;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/drive/DifferentialDrive.h b/wpilibc/src/main/native/include/frc/drive/DifferentialDrive.h
index 86103de..50a7a3f 100644
--- a/wpilibc/src/main/native/include/frc/drive/DifferentialDrive.h
+++ b/wpilibc/src/main/native/include/frc/drive/DifferentialDrive.h
@@ -1,20 +1,29 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/raw_ostream.h>
+#include <string>
+
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/drive/RobotDriveBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4996)  // was declared deprecated
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
 class SpeedController;
 
 /**
@@ -22,9 +31,9 @@
  * the Kit of Parts drive base, "tank drive", or West Coast Drive.
  *
  * 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
+ * wheels per side (e.g., 6WD or 8WD). This class takes a MotorController per
  * side. For four and six motor drivetrains, construct and pass in
- * SpeedControllerGroup instances as follows.
+ * MotorControllerGroup instances as follows.
  *
  * Four motor drivetrain:
  * @code{.cpp}
@@ -32,11 +41,11 @@
  *  public:
  *   frc::PWMVictorSPX m_frontLeft{1};
  *   frc::PWMVictorSPX m_rearLeft{2};
- *   frc::SpeedControllerGroup m_left{m_frontLeft, m_rearLeft};
+ *   frc::MotorControllerGroup m_left{m_frontLeft, m_rearLeft};
  *
  *   frc::PWMVictorSPX m_frontRight{3};
  *   frc::PWMVictorSPX m_rearRight{4};
- *   frc::SpeedControllerGroup m_right{m_frontRight, m_rearRight};
+ *   frc::MotorControllerGroup m_right{m_frontRight, m_rearRight};
  *
  *   frc::DifferentialDrive m_drive{m_left, m_right};
  * };
@@ -49,12 +58,12 @@
  *   frc::PWMVictorSPX m_frontLeft{1};
  *   frc::PWMVictorSPX m_midLeft{2};
  *   frc::PWMVictorSPX m_rearLeft{3};
- *   frc::SpeedControllerGroup m_left{m_frontLeft, m_midLeft, m_rearLeft};
+ *   frc::MotorControllerGroup m_left{m_frontLeft, m_midLeft, m_rearLeft};
  *
  *   frc::PWMVictorSPX m_frontRight{4};
  *   frc::PWMVictorSPX m_midRight{5};
  *   frc::PWMVictorSPX m_rearRight{6};
- *   frc::SpeedControllerGroup m_right{m_frontRight, m_midRight, m_rearRight};
+ *   frc::MotorControllerGroup m_right{m_frontRight, m_midRight, m_rearRight};
  *
  *   frc::DifferentialDrive m_drive{m_left, m_right};
  * };
@@ -87,28 +96,20 @@
  * Inputs smaller then 0.02 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 SetDeadband().
- *
- * <p>RobotDrive porting guide:
- * <br>TankDrive(double, double, bool) is equivalent to
- * RobotDrive#TankDrive(double, double, bool) if a deadband of 0 is used.
- * <br>ArcadeDrive(double, double, bool) is equivalent to
- * RobotDrive#ArcadeDrive(double, double, bool) if a deadband of 0 is used
- * and the the rotation input is inverted eg ArcadeDrive(y, -rotation, false)
- * <br>CurvatureDrive(double, double, bool) is similar in concept to
- * RobotDrive#Drive(double, double) with the addition of a quick turn
- * mode. However, it is not designed to give exactly the same response.
  */
 class DifferentialDrive : public RobotDriveBase,
-                          public Sendable,
-                          public SendableHelper<DifferentialDrive> {
+                          public wpi::Sendable,
+                          public wpi::SendableHelper<DifferentialDrive> {
  public:
-  static constexpr double kDefaultQuickStopThreshold = 0.2;
-  static constexpr double kDefaultQuickStopAlpha = 0.1;
+  struct WheelSpeeds {
+    double left = 0.0;
+    double right = 0.0;
+  };
 
   /**
    * Construct a DifferentialDrive.
    *
-   * To pass multiple motors per side, use a SpeedControllerGroup. If a motor
+   * To pass multiple motors per side, use a MotorControllerGroup. If a motor
    * needs to be inverted, do so before passing it in.
    */
   DifferentialDrive(SpeedController& leftMotor, SpeedController& rightMotor);
@@ -137,17 +138,16 @@
    *
    * 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.
+   * 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.
    */
-  void CurvatureDrive(double xSpeed, double zRotation, bool isQuickTurn);
+  void CurvatureDrive(double xSpeed, double zRotation, bool allowTurnInPlace);
 
   /**
    * Tank drive method for differential drive platform.
@@ -161,65 +161,65 @@
   void TankDrive(double leftSpeed, double rightSpeed, bool squareInputs = true);
 
   /**
-   * Sets the QuickStop speed threshold in curvature drive.
+   * Arcade drive inverse kinematics for differential drive platform.
    *
-   * QuickStop compensates for the robot's moment of inertia when stopping after
-   * a QuickTurn.
+   * Note: Some drivers may prefer inverted rotation controls. This can be done
+   * by negating the value passed for rotation.
    *
-   * 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].
+   * @param xSpeed       The speed at which the robot should drive along the X
+   *                     axis [-1.0..1.0]. Forward is positive.
+   * @param zRotation    The rotation rate of the robot around the Z axis
+   *                     [-1.0..1.0]. Clockwise is positive.
+   * @param squareInputs If set, decreases the input sensitivity at low speeds.
    */
-  void SetQuickStopThreshold(double threshold);
+  static WheelSpeeds ArcadeDriveIK(double xSpeed, double zRotation,
+                                   bool squareInputs = true);
 
   /**
-   * Sets the low-pass filter gain for QuickStop in curvature drive.
+   * Curvature drive inverse kinematics for differential drive platform.
    *
-   * The low-pass filter filters incoming rotation rate commands to smooth out
-   * high frequency changes.
+   * 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 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.
+   * @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.
    */
-  void SetQuickStopAlpha(double alpha);
+  static WheelSpeeds CurvatureDriveIK(double xSpeed, double zRotation,
+                                      bool allowTurnInPlace);
 
   /**
-   * Gets if the power sent to the right side of the drivetrain is multiplied by
-   * -1.
+   * Tank drive inverse kinematics for differential drive platform.
    *
-   * @return true if the right side is inverted
+   * @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.
    */
-  bool IsRightSideInverted() const;
-
-  /**
-   * 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
-   */
-  void SetRightSideInverted(bool rightSideInverted);
+  static WheelSpeeds TankDriveIK(double leftSpeed, double rightSpeed,
+                                 bool squareInputs = true);
 
   void StopMotor() override;
-  void GetDescription(wpi::raw_ostream& desc) const override;
+  std::string GetDescription() const override;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   SpeedController* m_leftMotor;
   SpeedController* m_rightMotor;
-
-  double m_quickStopThreshold = kDefaultQuickStopThreshold;
-  double m_quickStopAlpha = kDefaultQuickStopAlpha;
-  double m_quickStopAccumulator = 0.0;
-  double m_rightSideInvertMultiplier = -1.0;
 };
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#elif defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/drive/KilloughDrive.h b/wpilibc/src/main/native/include/frc/drive/KilloughDrive.h
index 2cc1c91..1acc69f 100644
--- a/wpilibc/src/main/native/include/frc/drive/KilloughDrive.h
+++ b/wpilibc/src/main/native/include/frc/drive/KilloughDrive.h
@@ -1,23 +1,31 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
+#include <string>
 
-#include <wpi/raw_ostream.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/drive/RobotDriveBase.h"
 #include "frc/drive/Vector2d.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4996)  // was declared deprecated
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
 class SpeedController;
 
 /**
@@ -47,13 +55,19 @@
  * clockwise rotation around the Z axis is positive.
  */
 class KilloughDrive : public RobotDriveBase,
-                      public Sendable,
-                      public SendableHelper<KilloughDrive> {
+                      public wpi::Sendable,
+                      public wpi::SendableHelper<KilloughDrive> {
  public:
   static constexpr double kDefaultLeftMotorAngle = 60.0;
   static constexpr double kDefaultRightMotorAngle = 120.0;
   static constexpr double kDefaultBackMotorAngle = 270.0;
 
+  struct WheelSpeeds {
+    double left = 0.0;
+    double right = 0.0;
+    double back = 0.0;
+  };
+
   /**
    * Construct a Killough drive with the given motors and default motor angles.
    *
@@ -126,10 +140,28 @@
    */
   void DrivePolar(double magnitude, double angle, double zRotation);
 
-  void StopMotor() override;
-  void GetDescription(wpi::raw_ostream& desc) const override;
+  /**
+   * Cartesian inverse kinematics for Killough platform.
+   *
+   * 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.
+   */
+  WheelSpeeds DriveCartesianIK(double ySpeed, double xSpeed, double zRotation,
+                               double gyroAngle = 0.0);
 
-  void InitSendable(SendableBuilder& builder) override;
+  void StopMotor() override;
+  std::string GetDescription() const override;
+
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   SpeedController* m_leftMotor;
@@ -143,4 +175,12 @@
   bool reported = false;
 };
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#elif defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/drive/MecanumDrive.h b/wpilibc/src/main/native/include/frc/drive/MecanumDrive.h
index 8435b4d..809e7ea 100644
--- a/wpilibc/src/main/native/include/frc/drive/MecanumDrive.h
+++ b/wpilibc/src/main/native/include/frc/drive/MecanumDrive.h
@@ -1,22 +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.
 
 #pragma once
 
 #include <memory>
+#include <string>
 
-#include <wpi/raw_ostream.h>
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 #include "frc/drive/RobotDriveBase.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
 
 namespace frc {
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4996)  // was declared deprecated
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
 class SpeedController;
 
 /**
@@ -52,22 +60,29 @@
  * with SetDeadband().
  *
  * RobotDrive porting guide:
- * <br>In MecanumDrive, the right side speed controllers are automatically
- * inverted, while in RobotDrive, no speed controllers are automatically
+ * <br>In MecanumDrive, the right side motor controllers are automatically
+ * inverted, while in RobotDrive, no motor controllers are automatically
  * inverted.
  * <br>DriveCartesian(double, double, double, double) is equivalent to
- * RobotDrive#MecanumDrive_Cartesian(double, double, double, double)
+ * 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>DrivePolar(double, double, double) is equivalent to
- * RobotDrive#MecanumDrive_Polar(double, double, double) if a
+ * RobotDrive's MecanumDrive_Polar(double, double, double) if a
  * deadband of 0 is used.
  */
 class MecanumDrive : public RobotDriveBase,
-                     public Sendable,
-                     public SendableHelper<MecanumDrive> {
+                     public wpi::Sendable,
+                     public wpi::SendableHelper<MecanumDrive> {
  public:
+  struct WheelSpeeds {
+    double frontLeft = 0.0;
+    double frontRight = 0.0;
+    double rearLeft = 0.0;
+    double rearRight = 0.0;
+  };
+
   /**
    * Construct a MecanumDrive.
    *
@@ -116,26 +131,27 @@
   void DrivePolar(double magnitude, double angle, double zRotation);
 
   /**
-   * 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
-   */
-  bool IsRightSideInverted() const;
-
-  /**
-   * Sets if the power sent to the right side of the drivetrain should be
-   * multiplied by -1.
+   * Angles are measured clockwise from the positive X axis. The robot's speed
+   * is independent from its angle or rotation rate.
    *
-   * @param rightSideInverted true if right side power should be multiplied by
-   * -1
+   * @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.
    */
-  void SetRightSideInverted(bool rightSideInverted);
+  static WheelSpeeds DriveCartesianIK(double ySpeed, double xSpeed,
+                                      double zRotation, double gyroAngle = 0.0);
 
   void StopMotor() override;
-  void GetDescription(wpi::raw_ostream& desc) const override;
+  std::string GetDescription() const override;
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   SpeedController* m_frontLeftMotor;
@@ -143,9 +159,15 @@
   SpeedController* m_frontRightMotor;
   SpeedController* m_rearRightMotor;
 
-  double m_rightSideInvertMultiplier = -1.0;
-
   bool reported = false;
 };
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#elif defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/drive/RobotDriveBase.h b/wpilibc/src/main/native/include/frc/drive/RobotDriveBase.h
index ce9cbc5..389d67b 100644
--- a/wpilibc/src/main/native/include/frc/drive/RobotDriveBase.h
+++ b/wpilibc/src/main/native/include/frc/drive/RobotDriveBase.h
@@ -1,23 +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.
 
 #pragma once
 
 #include <memory>
+#include <string>
 
-#include <wpi/ArrayRef.h>
-#include <wpi/raw_ostream.h>
+#include <wpi/deprecated.h>
+#include <wpi/span.h>
 
 #include "frc/MotorSafety.h"
 
 namespace frc {
 
-class SpeedController;
-
 /**
  * Common base class for drive platforms.
  */
@@ -47,7 +43,7 @@
    *
    * The default value is 0.02. 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
-   * ApplyDeadband().
+   * frc::ApplyDeadband().
    *
    * @param deadband The deadband to set.
    */
@@ -71,7 +67,7 @@
   void FeedWatchdog();
 
   void StopMotor() override = 0;
-  void GetDescription(wpi::raw_ostream& desc) const override = 0;
+  std::string GetDescription() const override = 0;
 
  protected:
   /**
@@ -80,14 +76,16 @@
    *
    * @param value    value to clip
    * @param deadband range around zero
+   * @deprecated Use ApplyDeadband() in frc/MathUtil.h.
    */
-  double ApplyDeadband(double number, double deadband);
+  WPI_DEPRECATED("Use ApplyDeadband() in frc/MathUtil.h")
+  static double ApplyDeadband(double value, double deadband);
 
   /**
    * Normalize all wheel speeds if the magnitude of any wheel is greater than
    * 1.0.
    */
-  void Normalize(wpi::MutableArrayRef<double> wheelSpeeds);
+  static void Normalize(wpi::span<double> wheelSpeeds);
 
   double m_deadband = 0.02;
   double m_maxOutput = 1.0;
diff --git a/wpilibc/src/main/native/include/frc/drive/Vector2d.h b/wpilibc/src/main/native/include/frc/drive/Vector2d.h
index c9bd08a..92a3de6 100644
--- a/wpilibc/src/main/native/include/frc/drive/Vector2d.h
+++ b/wpilibc/src/main/native/include/frc/drive/Vector2d.h
@@ -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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/filters/Filter.h b/wpilibc/src/main/native/include/frc/filters/Filter.h
deleted file mode 100644
index fb14d28..0000000
--- a/wpilibc/src/main/native/include/frc/filters/Filter.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* 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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-
-#include <wpi/deprecated.h>
-
-#include "frc/PIDSource.h"
-
-namespace frc {
-
-/**
- * Interface for filters
- *
- * @deprecated only used by the deprecated LinearDigitalFilter
- */
-class Filter : public PIDSource {
- public:
-  WPI_DEPRECATED("This class is no longer used.")
-  explicit Filter(PIDSource& source);
-  WPI_DEPRECATED("This class is no longer used.")
-  explicit Filter(std::shared_ptr<PIDSource> source);
-  virtual ~Filter() = default;
-
-  Filter(Filter&&) = default;
-  Filter& operator=(Filter&&) = default;
-
-  // PIDSource interface
-  void SetPIDSourceType(PIDSourceType pidSource) override;
-  PIDSourceType GetPIDSourceType() const override;
-  double PIDGet() override = 0;
-
-  /**
-   * Returns the current filter estimate without also inserting new data as
-   * PIDGet() would do.
-   *
-   * @return The current filter estimate
-   */
-  virtual double Get() const = 0;
-
-  /**
-   * Reset the filter state
-   */
-  virtual void Reset() = 0;
-
- protected:
-  /**
-   * Calls PIDGet() of source
-   *
-   * @return Current value of source
-   */
-  double PIDGetSource();
-
- private:
-  std::shared_ptr<PIDSource> m_source;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/filters/LinearDigitalFilter.h b/wpilibc/src/main/native/include/frc/filters/LinearDigitalFilter.h
deleted file mode 100644
index c4fc3ef..0000000
--- a/wpilibc/src/main/native/include/frc/filters/LinearDigitalFilter.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* 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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <initializer_list>
-#include <memory>
-#include <vector>
-
-#include <wpi/ArrayRef.h>
-#include <wpi/circular_buffer.h>
-#include <wpi/deprecated.h>
-
-#include "frc/filters/Filter.h"
-
-namespace frc {
-
-/**
- * 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.
- *
- * Filters are of the form:<br>
- *  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])
- *
- * Where:<br>
- *  y[n] is the output at time "n"<br>
- *  x[n] is the input at time "n"<br>
- *  y[n-1] is the output from the LAST time step ("n-1")<br>
- *  x[n-1] is the input from the LAST time step ("n-1")<br>
- *  b0...bP are the "feedforward" (FIR) gains<br>
- *  a0...aQ are the "feedback" (IIR) gains<br>
- * IMPORTANT! Note the "-" sign in front of the feedback term! This is a common
- *            convention in signal processing.
- *
- * 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.
- *
- * 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!
- *
- * For more on filters, I highly recommend the following articles:<br>
- *  http://en.wikipedia.org/wiki/Linear_filter<br>
- *  http://en.wikipedia.org/wiki/Iir_filter<br>
- *  http://en.wikipedia.org/wiki/Fir_filter<br>
- *
- * 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.
- *
- * 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
- */
-class LinearDigitalFilter : public Filter {
- public:
-  /**
-   * 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
-   */
-  WPI_DEPRECATED("Use LinearFilter class instead.")
-  LinearDigitalFilter(PIDSource& source, wpi::ArrayRef<double> ffGains,
-                      wpi::ArrayRef<double> fbGains);
-
-  /**
-   * 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
-   */
-  WPI_DEPRECATED("Use LinearFilter class instead.")
-  LinearDigitalFilter(PIDSource& source, std::initializer_list<double> ffGains,
-                      std::initializer_list<double> fbGains);
-
-  /**
-   * 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
-   */
-  WPI_DEPRECATED("Use LinearFilter class instead.")
-  LinearDigitalFilter(std::shared_ptr<PIDSource> source,
-                      wpi::ArrayRef<double> ffGains,
-                      wpi::ArrayRef<double> fbGains);
-
-  /**
-   * 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
-   */
-  WPI_DEPRECATED("Use LinearFilter class instead.")
-  LinearDigitalFilter(std::shared_ptr<PIDSource> source,
-                      std::initializer_list<double> ffGains,
-                      std::initializer_list<double> fbGains);
-
-  LinearDigitalFilter(LinearDigitalFilter&&) = default;
-  LinearDigitalFilter& operator=(LinearDigitalFilter&&) = default;
-
-  // Static methods to create commonly used filters
-  /**
-   * Creates a one-pole IIR low-pass filter of the form:<br>
-   *   y[n] = (1 - gain) * x[n] + gain * y[n-1]<br>
-   * where gain = e<sup>-dt / T</sup>, T is the time constant in seconds
-   *
-   * 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
-   */
-  static LinearDigitalFilter SinglePoleIIR(PIDSource& source,
-                                           double timeConstant, double period);
-
-  /**
-   * Creates a first-order high-pass filter of the form:<br>
-   *   y[n] = gain * x[n] + (-gain) * x[n-1] + gain * y[n-1]<br>
-   * where gain = e<sup>-dt / T</sup>, T is the time constant in seconds
-   *
-   * 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
-   */
-  static LinearDigitalFilter HighPass(PIDSource& source, double timeConstant,
-                                      double period);
-
-  /**
-   * Creates a K-tap FIR moving average filter of the form:<br>
-   *   y[n] = 1/k * (x[k] + x[k-1] + … + x[0])
-   *
-   * 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
-   */
-  static LinearDigitalFilter MovingAverage(PIDSource& source, int taps);
-
-  /**
-   * Creates a one-pole IIR low-pass filter of the form:<br>
-   *   y[n] = (1 - gain) * x[n] + gain * y[n-1]<br>
-   * where gain = e<sup>-dt / T</sup>, T is the time constant in seconds
-   *
-   * 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
-   */
-  static LinearDigitalFilter SinglePoleIIR(std::shared_ptr<PIDSource> source,
-                                           double timeConstant, double period);
-
-  /**
-   * Creates a first-order high-pass filter of the form:<br>
-   *   y[n] = gain * x[n] + (-gain) * x[n-1] + gain * y[n-1]<br>
-   * where gain = e<sup>-dt / T</sup>, T is the time constant in seconds
-   *
-   * 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
-   */
-  static LinearDigitalFilter HighPass(std::shared_ptr<PIDSource> source,
-                                      double timeConstant, double period);
-
-  /**
-   * Creates a K-tap FIR moving average filter of the form:<br>
-   *   y[n] = 1/k * (x[k] + x[k-1] + … + x[0])
-   *
-   * 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
-   */
-  static LinearDigitalFilter MovingAverage(std::shared_ptr<PIDSource> source,
-                                           int taps);
-
-  // Filter interface
-  double Get() const override;
-  void Reset() override;
-
-  // PIDSource interface
-  /**
-   * Calculates the next value of the filter
-   *
-   * @return The filtered value at this step
-   */
-  double PIDGet() override;
-
- private:
-  wpi::circular_buffer<double> m_inputs;
-  wpi::circular_buffer<double> m_outputs;
-  std::vector<double> m_inputGains;
-  std::vector<double> m_outputGains;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/interfaces/Accelerometer.h b/wpilibc/src/main/native/include/frc/interfaces/Accelerometer.h
index 499ba5b..c95466a 100644
--- a/wpilibc/src/main/native/include/frc/interfaces/Accelerometer.h
+++ b/wpilibc/src/main/native/include/frc/interfaces/Accelerometer.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/interfaces/Gyro.h b/wpilibc/src/main/native/include/frc/interfaces/Gyro.h
index 8c06993..50417ea 100644
--- a/wpilibc/src/main/native/include/frc/interfaces/Gyro.h
+++ b/wpilibc/src/main/native/include/frc/interfaces/Gyro.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/interfaces/Potentiometer.h b/wpilibc/src/main/native/include/frc/interfaces/Potentiometer.h
deleted file mode 100644
index 219e6ba..0000000
--- a/wpilibc/src/main/native/include/frc/interfaces/Potentiometer.h
+++ /dev/null
@@ -1,35 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include "frc/PIDSource.h"
-
-namespace frc {
-
-/**
- * Interface for potentiometers.
- */
-class Potentiometer : public PIDSource {
- public:
-  Potentiometer() = default;
-  virtual ~Potentiometer() = default;
-
-  Potentiometer(Potentiometer&&) = default;
-  Potentiometer& operator=(Potentiometer&&) = default;
-
-  /**
-   * Common interface for getting the current value of a potentiometer.
-   *
-   * @return The current set speed. Value is between -1.0 and 1.0.
-   */
-  virtual double Get() const = 0;
-
-  void SetPIDSourceType(PIDSourceType pidSource) override;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/livewindow/LiveWindow.h b/wpilibc/src/main/native/include/frc/livewindow/LiveWindow.h
index b755f46..6851cde 100644
--- a/wpilibc/src/main/native/include/frc/livewindow/LiveWindow.h
+++ b/wpilibc/src/main/native/include/frc/livewindow/LiveWindow.h
@@ -1,66 +1,77 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2012-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.
 
 #pragma once
 
 #include <functional>
-#include <memory>
+
+#include <wpi/deprecated.h>
+
+namespace wpi {
+class Sendable;
+}  // namespace wpi
 
 namespace frc {
 
-class Sendable;
-
 /**
  * The LiveWindow class is the public interface for putting sensors and
  * actuators on the LiveWindow.
  */
 class LiveWindow {
  public:
-  LiveWindow(const LiveWindow&) = delete;
-  LiveWindow& operator=(const LiveWindow&) = delete;
-
-  std::function<void()> enabled;
-  std::function<void()> disabled;
-
   /**
    * Get an instance of the LiveWindow main class.
    *
    * This is a singleton to guarantee that there is only a single instance
    * regardless of how many times GetInstance is called.
+   * @deprecated Use the static methods unless guaranteeing LiveWindow is
+   * instantiated
    */
+  WPI_DEPRECATED("Use static methods")
   static LiveWindow* GetInstance();
 
   /**
+   * Set function to be called when LiveWindow is enabled.
+   *
+   * @param func function (or nullptr for none)
+   */
+  static void SetEnabledCallback(std::function<void()> func);
+
+  /**
+   * Set function to be called when LiveWindow is disabled.
+   *
+   * @param func function (or nullptr for none)
+   */
+  static void SetDisabledCallback(std::function<void()> func);
+
+  /**
    * Enable telemetry for a single component.
    *
-   * @param sendable component
+   * @param component sendable
    */
-  void EnableTelemetry(Sendable* component);
+  static void EnableTelemetry(wpi::Sendable* component);
 
   /**
    * Disable telemetry for a single component.
    *
-   * @param sendable component
+   * @param component sendable
    */
-  void DisableTelemetry(Sendable* component);
+  static void DisableTelemetry(wpi::Sendable* component);
 
   /**
    * Disable ALL telemetry.
    */
-  void DisableAllTelemetry();
+  static void DisableAllTelemetry();
 
-  bool IsEnabled() const;
+  static bool IsEnabled();
 
   /**
    * Change the enabled status of LiveWindow.
    *
    * If it changes to enabled, start livewindow running otherwise stop it
    */
-  void SetEnabled(bool enabled);
+  static void SetEnabled(bool enabled);
 
   /**
    * Tell all the sensors to update (send) their values.
@@ -68,18 +79,15 @@
    * Actuators are handled through callbacks on their value changing from the
    * SmartDashboard widgets.
    */
-  void UpdateValues();
+  static void UpdateValues();
 
  private:
-  LiveWindow();
-
-  struct Impl;
-  std::unique_ptr<Impl> m_impl;
+  LiveWindow() = default;
 
   /**
    * Updates the entries, without using a mutex or lock.
    */
-  void UpdateValuesUnsafe();
+  static void UpdateValuesUnsafe();
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/DMC60.h b/wpilibc/src/main/native/include/frc/motorcontrol/DMC60.h
similarity index 62%
rename from wpilibc/src/main/native/include/frc/DMC60.h
rename to wpilibc/src/main/native/include/frc/motorcontrol/DMC60.h
index ecf01e1..f47826a 100644
--- a/wpilibc/src/main/native/include/frc/DMC60.h
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/DMC60.h
@@ -1,18 +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.
 
 #pragma once
 
-#include "frc/PWMSpeedController.h"
+#include "frc/motorcontrol/PWMMotorController.h"
 
 namespace frc {
 
 /**
- * Digilent DMC 60 Speed Controller.
+ * Digilent DMC 60 Motor %Controller.
  *
  * Note that the DMC 60 uses the following bounds for PWM values. These
  * values should work reasonably well for most controllers, but if users
@@ -27,7 +24,7 @@
  * \li 1.480ms = the "low end" of the deadband range
  * \li 0.997ms = full "reverse"
  */
-class DMC60 : public PWMSpeedController {
+class DMC60 : public PWMMotorController {
  public:
   /**
    * Constructor for a Digilent DMC 60.
diff --git a/wpilibc/src/main/native/include/frc/Jaguar.h b/wpilibc/src/main/native/include/frc/motorcontrol/Jaguar.h
similarity index 61%
rename from wpilibc/src/main/native/include/frc/Jaguar.h
rename to wpilibc/src/main/native/include/frc/motorcontrol/Jaguar.h
index 7a8503e..d25a457 100644
--- a/wpilibc/src/main/native/include/frc/Jaguar.h
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/Jaguar.h
@@ -1,18 +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.
 
 #pragma once
 
-#include "frc/PWMSpeedController.h"
+#include "frc/motorcontrol/PWMMotorController.h"
 
 namespace frc {
 
 /**
- * Luminary Micro / Vex Robotics Jaguar Speed Controller with PWM control.
+ * Luminary Micro / Vex Robotics Jaguar Motor %Controller with PWM control.
  *
  * Note that the Jaguar uses the following bounds for PWM values. These values
  * should work reasonably well for most controllers, but if users experience
@@ -27,7 +24,7 @@
  * \li 1.454ms = the "low end" of the deadband range
  * \li 0.697ms = full "reverse"
  */
-class Jaguar : public PWMSpeedController {
+class Jaguar : public PWMMotorController {
  public:
   /**
    * Constructor for a Jaguar connected via PWM.
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/MotorController.h b/wpilibc/src/main/native/include/frc/motorcontrol/MotorController.h
new file mode 100644
index 0000000..8ed19bc
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/MotorController.h
@@ -0,0 +1,37 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <units/voltage.h>
+
+#include "frc/SpeedController.h"
+
+namespace frc {
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4996)  // was declared deprecated
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+/**
+ * Interface for motor controlling devices.
+ */
+class MotorController : public SpeedController {};
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#elif defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/MotorControllerGroup.h b/wpilibc/src/main/native/include/frc/motorcontrol/MotorControllerGroup.h
new file mode 100644
index 0000000..6f47bf9
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/MotorControllerGroup.h
@@ -0,0 +1,51 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <functional>
+#include <vector>
+
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
+#include "frc/motorcontrol/MotorController.h"
+
+namespace frc {
+
+/**
+ * Allows multiple MotorController objects to be linked together.
+ */
+class MotorControllerGroup : public wpi::Sendable,
+                             public MotorController,
+                             public wpi::SendableHelper<MotorControllerGroup> {
+ public:
+  template <class... MotorControllers>
+  explicit MotorControllerGroup(MotorController& motorController,
+                                MotorControllers&... motorControllers);
+  explicit MotorControllerGroup(
+      std::vector<std::reference_wrapper<MotorController>>&& motorControllers);
+
+  MotorControllerGroup(MotorControllerGroup&&) = default;
+  MotorControllerGroup& operator=(MotorControllerGroup&&) = default;
+
+  void Set(double speed) override;
+  double Get() const override;
+  void SetInverted(bool isInverted) override;
+  bool GetInverted() const override;
+  void Disable() override;
+  void StopMotor() override;
+
+  void InitSendable(wpi::SendableBuilder& builder) override;
+
+ private:
+  bool m_isInverted = false;
+  std::vector<std::reference_wrapper<MotorController>> m_motorControllers;
+
+  void Initialize();
+};
+
+}  // namespace frc
+
+#include "frc/motorcontrol/MotorControllerGroup.inc"
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/MotorControllerGroup.inc b/wpilibc/src/main/native/include/frc/motorcontrol/MotorControllerGroup.inc
new file mode 100644
index 0000000..8f87635
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/MotorControllerGroup.inc
@@ -0,0 +1,22 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <functional>
+#include <vector>
+
+#include "frc/motorcontrol/MotorControllerGroup.h"
+
+namespace frc {
+
+template <class... MotorControllers>
+MotorControllerGroup::MotorControllerGroup(
+    MotorController& motorController, MotorControllers&... motorControllers)
+    : m_motorControllers(std::vector<std::reference_wrapper<MotorController>>{
+          motorController, motorControllers...}) {
+  Initialize();
+}
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/NidecBrushless.h b/wpilibc/src/main/native/include/frc/motorcontrol/NidecBrushless.h
similarity index 61%
rename from wpilibc/src/main/native/include/frc/NidecBrushless.h
rename to wpilibc/src/main/native/include/frc/motorcontrol/NidecBrushless.h
index fa77e28..cc95d71 100644
--- a/wpilibc/src/main/native/include/frc/NidecBrushless.h
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/NidecBrushless.h
@@ -1,31 +1,28 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
+#include <string>
+
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
 #include "frc/DigitalOutput.h"
-#include "frc/ErrorBase.h"
 #include "frc/MotorSafety.h"
 #include "frc/PWM.h"
-#include "frc/SpeedController.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include "frc/motorcontrol/MotorController.h"
 
 namespace frc {
 
-class SendableBuilder;
-
 /**
  * Nidec Brushless Motor.
  */
-class NidecBrushless : public SpeedController,
+class NidecBrushless : public MotorController,
                        public MotorSafety,
-                       public Sendable,
-                       public SendableHelper<NidecBrushless> {
+                       public wpi::Sendable,
+                       public wpi::SendableHelper<NidecBrushless> {
  public:
   /**
    * Constructor.
@@ -42,7 +39,7 @@
   NidecBrushless(NidecBrushless&&) = default;
   NidecBrushless& operator=(NidecBrushless&&) = default;
 
-  // SpeedController interface
+  // MotorController interface
   /**
    * Set the PWM value.
    *
@@ -76,17 +73,9 @@
    */
   void Enable();
 
-  // PIDOutput interface
-  /**
-   * 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
-   */
-  void PIDWrite(double output) override;
-
   // MotorSafety interface
   void StopMotor() override;
-  void GetDescription(wpi::raw_ostream& desc) const override;
+  std::string GetDescription() const override;
 
   /**
    * Gets the channel number associated with the object.
@@ -96,7 +85,7 @@
   int GetChannel() const;
 
   // Sendable interface
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   bool m_isInverted = false;
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/PWMMotorController.h b/wpilibc/src/main/native/include/frc/motorcontrol/PWMMotorController.h
new file mode 100644
index 0000000..ac6ba4b
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/PWMMotorController.h
@@ -0,0 +1,84 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <string>
+#include <string_view>
+
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
+
+#include "frc/MotorSafety.h"
+#include "frc/PWM.h"
+#include "frc/motorcontrol/MotorController.h"
+
+namespace frc {
+class DMA;
+
+/**
+ * Common base class for all PWM Motor Controllers.
+ */
+class PWMMotorController : public MotorController,
+                           public MotorSafety,
+                           public wpi::Sendable,
+                           public wpi::SendableHelper<PWMMotorController> {
+ public:
+  friend class DMA;
+
+  PWMMotorController(PWMMotorController&&) = default;
+  PWMMotorController& operator=(PWMMotorController&&) = default;
+
+  /**
+   * Set the PWM value.
+   *
+   * The PWM value is set using a range of -1.0 to 1.0, appropriately scaling
+   * the value for the FPGA.
+   *
+   * @param value The speed value between -1.0 and 1.0 to set.
+   */
+  void Set(double value) override;
+
+  /**
+   * 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 PWM::GetSpeed() instead.
+   *
+   * @return The most recently set value for the PWM between -1.0 and 1.0.
+   */
+  double Get() const override;
+
+  void SetInverted(bool isInverted) override;
+
+  bool GetInverted() const override;
+
+  void Disable() override;
+
+  // MotorSafety interface
+  void StopMotor() override;
+  std::string GetDescription() const override;
+
+  int GetChannel() const;
+
+ protected:
+  /**
+   * Constructor for a PWM Motor %Controller connected via PWM.
+   *
+   * @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
+   */
+  PWMMotorController(std::string_view name, int channel);
+
+  void InitSendable(wpi::SendableBuilder& builder) override;
+
+  PWM m_pwm;
+
+ private:
+  bool m_isInverted = false;
+
+  PWM* GetPwm() { return &m_pwm; }
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PWMSparkMax.h b/wpilibc/src/main/native/include/frc/motorcontrol/PWMSparkMax.h
similarity index 62%
rename from wpilibc/src/main/native/include/frc/PWMSparkMax.h
rename to wpilibc/src/main/native/include/frc/motorcontrol/PWMSparkMax.h
index 3ce6466..45c7bae 100644
--- a/wpilibc/src/main/native/include/frc/PWMSparkMax.h
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/PWMSparkMax.h
@@ -1,18 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include "frc/PWMSpeedController.h"
+#include "frc/motorcontrol/PWMMotorController.h"
 
 namespace frc {
 
 /**
- * REV Robotics SPARK MAX Speed Controller.
+ * REV Robotics SPARK MAX Motor %Controller.
  *
  * Note that the SPARK MAX uses the following bounds for PWM values. These
  * values should work reasonably well for most controllers, but if users
@@ -27,7 +24,7 @@
  * \li 1.460ms = the "low end" of the deadband range
  * \li 0.999ms = full "reverse"
  */
-class PWMSparkMax : public PWMSpeedController {
+class PWMSparkMax : public PWMMotorController {
  public:
   /**
    * Constructor for a SPARK MAX.
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/PWMTalonFX.h b/wpilibc/src/main/native/include/frc/motorcontrol/PWMTalonFX.h
new file mode 100644
index 0000000..29aada6
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/PWMTalonFX.h
@@ -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.
+
+#pragma once
+
+#include "frc/motorcontrol/PWMMotorController.h"
+
+namespace frc {
+
+/**
+ * Cross the Road Electronics (CTRE) %Talon FX Motor %Controller with PWM
+ * control.
+ *
+ * Note that the %Talon FX 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 FX User
+ * Manual available from Cross The Road Electronics.
+ *
+ * \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"
+ */
+class PWMTalonFX : public PWMMotorController {
+ public:
+  /**
+   * Construct a %Talon FX 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
+   */
+  explicit PWMTalonFX(int channel);
+
+  PWMTalonFX(PWMTalonFX&&) = default;
+  PWMTalonFX& operator=(PWMTalonFX&&) = default;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/PWMTalonSRX.h b/wpilibc/src/main/native/include/frc/motorcontrol/PWMTalonSRX.h
new file mode 100644
index 0000000..9f9e384
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/PWMTalonSRX.h
@@ -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.
+
+#pragma once
+
+#include "frc/motorcontrol/PWMMotorController.h"
+
+namespace frc {
+
+/**
+ * Cross the Road Electronics (CTRE) %Talon SRX Motor %Controller with PWM
+ * control.
+ *
+ * Note that the %Talon SRX 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 SRX User
+ * Manual available from Cross The Road Electronics.
+ *
+ * \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"
+ */
+class PWMTalonSRX : public PWMMotorController {
+ public:
+  /**
+   * Construct a %Talon SRX 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
+   */
+  explicit PWMTalonSRX(int channel);
+
+  PWMTalonSRX(PWMTalonSRX&&) = default;
+  PWMTalonSRX& operator=(PWMTalonSRX&&) = default;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/PWMVenom.h b/wpilibc/src/main/native/include/frc/motorcontrol/PWMVenom.h
similarity index 63%
rename from wpilibc/src/main/native/include/frc/PWMVenom.h
rename to wpilibc/src/main/native/include/frc/motorcontrol/PWMVenom.h
index 189db43..1047e8e 100644
--- a/wpilibc/src/main/native/include/frc/PWMVenom.h
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/PWMVenom.h
@@ -1,13 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include "frc/PWMSpeedController.h"
+#include "frc/motorcontrol/PWMMotorController.h"
 
 namespace frc {
 
@@ -26,7 +23,7 @@
  * \li 1.480ms = the "low end" of the deadband range
  * \li 0.997ms = full "reverse"
  */
-class PWMVenom : public PWMSpeedController {
+class PWMVenom : public PWMMotorController {
  public:
   /**
    * Construct a Venom connected via PWM.
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/PWMVictorSPX.h b/wpilibc/src/main/native/include/frc/motorcontrol/PWMVictorSPX.h
new file mode 100644
index 0000000..b6bb324
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/PWMVictorSPX.h
@@ -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.
+
+#pragma once
+
+#include "frc/motorcontrol/PWMMotorController.h"
+
+namespace frc {
+
+/**
+ * Cross the Road Electronics (CTRE) %Victor SPX Motor %Controller with PWM
+ * control.
+ *
+ * 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 Cross The Road Electronics.
+ *
+ * \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"
+ */
+class PWMVictorSPX : public PWMMotorController {
+ public:
+  /**
+   * Construct a %Victor SPX connected via PWM.
+   *
+   * @param channel The PWM channel that the %Victor SPX is attached to. 0-9
+   *                are on-board, 10-19 are on the MXP port
+   */
+  explicit PWMVictorSPX(int channel);
+
+  PWMVictorSPX(PWMVictorSPX&&) = default;
+  PWMVictorSPX& operator=(PWMVictorSPX&&) = default;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/SD540.h b/wpilibc/src/main/native/include/frc/motorcontrol/SD540.h
similarity index 61%
rename from wpilibc/src/main/native/include/frc/SD540.h
rename to wpilibc/src/main/native/include/frc/motorcontrol/SD540.h
index 07f7f18..44a0c8c 100644
--- a/wpilibc/src/main/native/include/frc/SD540.h
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/SD540.h
@@ -1,18 +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.
 
 #pragma once
 
-#include "frc/PWMSpeedController.h"
+#include "frc/motorcontrol/PWMMotorController.h"
 
 namespace frc {
 
 /**
- * Mindsensors SD540 Speed Controller.
+ * Mindsensors SD540 Motor %Controller.
  *
  * Note that the SD540 uses the following bounds for PWM values. These values
  * should work reasonably well for most controllers, but if users experience
@@ -27,7 +24,7 @@
  * \li 1.44ms = the "low end" of the deadband range
  * \li 0.94ms = full "reverse"
  */
-class SD540 : public PWMSpeedController {
+class SD540 : public PWMMotorController {
  public:
   /**
    * Constructor for a SD540.
diff --git a/wpilibc/src/main/native/include/frc/Spark.h b/wpilibc/src/main/native/include/frc/motorcontrol/Spark.h
similarity index 62%
rename from wpilibc/src/main/native/include/frc/Spark.h
rename to wpilibc/src/main/native/include/frc/motorcontrol/Spark.h
index 24ed8f5..6163234 100644
--- a/wpilibc/src/main/native/include/frc/Spark.h
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/Spark.h
@@ -1,18 +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.
 
 #pragma once
 
-#include "frc/PWMSpeedController.h"
+#include "frc/motorcontrol/PWMMotorController.h"
 
 namespace frc {
 
 /**
- * REV Robotics SPARK Speed Controller.
+ * REV Robotics SPARK Motor %Controller.
  *
  * Note that the SPARK uses the following bounds for PWM values. These values
  * should work reasonably well for most controllers, but if users experience
@@ -27,7 +24,7 @@
  * \li 1.460ms = the "low end" of the deadband range
  * \li 0.999ms = full "reverse"
  */
-class Spark : public PWMSpeedController {
+class Spark : public PWMMotorController {
  public:
   /**
    * Constructor for a SPARK.
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/Talon.h b/wpilibc/src/main/native/include/frc/motorcontrol/Talon.h
new file mode 100644
index 0000000..acf5c55
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/Talon.h
@@ -0,0 +1,41 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include "frc/motorcontrol/PWMMotorController.h"
+
+namespace frc {
+
+/**
+ * Cross the Road Electronics (CTRE) %Talon and %Talon SR Motor %Controller.
+ *
+ * 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.
+ *
+ * \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"
+ */
+class Talon : public PWMMotorController {
+ public:
+  /**
+   * Constructor for a %Talon (original or %Talon SR).
+   *
+   * @param channel The PWM channel number that the %Talon is attached to. 0-9
+   *                are on-board, 10-19 are on the MXP port
+   */
+  explicit Talon(int channel);
+
+  Talon(Talon&&) = default;
+  Talon& operator=(Talon&&) = default;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/Victor.h b/wpilibc/src/main/native/include/frc/motorcontrol/Victor.h
new file mode 100644
index 0000000..9627925
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/Victor.h
@@ -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.
+
+#pragma once
+
+#include "frc/motorcontrol/PWMMotorController.h"
+
+namespace frc {
+
+/**
+ * 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.
+ *
+ * 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 as well 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.
+ *
+ * \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"
+ */
+class Victor : public PWMMotorController {
+ public:
+  /**
+   * Constructor for a %Victor.
+   *
+   * @param channel The PWM channel number that the %Victor is attached to. 0-9
+   *                are on-board, 10-19 are on the MXP port
+   */
+  explicit Victor(int channel);
+
+  Victor(Victor&&) = default;
+  Victor& operator=(Victor&&) = default;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/motorcontrol/VictorSP.h b/wpilibc/src/main/native/include/frc/motorcontrol/VictorSP.h
new file mode 100644
index 0000000..f599ff4
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/motorcontrol/VictorSP.h
@@ -0,0 +1,41 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include "frc/motorcontrol/PWMMotorController.h"
+
+namespace frc {
+
+/**
+ * Vex Robotics %Victor SP Motor %Controller.
+ *
+ * Note that the %Victor SP 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 SP User
+ * Manual available from Vex.
+ *
+ * \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"
+ */
+class VictorSP : public PWMMotorController {
+ public:
+  /**
+   * Constructor for a %Victor SP.
+   *
+   * @param channel The PWM channel that the Victor SP is attached to. 0-9 are
+   *                on-board, 10-19 are on the MXP port
+   */
+  explicit VictorSP(int channel);
+
+  VictorSP(VictorSP&&) = default;
+  VictorSP& operator=(VictorSP&&) = default;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/BuiltInLayouts.h b/wpilibc/src/main/native/include/frc/shuffleboard/BuiltInLayouts.h
index 1d1ea5f..ca5e29f 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/BuiltInLayouts.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/BuiltInLayouts.h
@@ -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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/BuiltInWidgets.h b/wpilibc/src/main/native/include/frc/shuffleboard/BuiltInWidgets.h
index df943b2..9ac315f 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/BuiltInWidgets.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/BuiltInWidgets.h
@@ -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.
 
 #pragma once
 
@@ -163,8 +160,8 @@
    */
   kVoltageView,
   /**
-   * Displays a PowerDistributionPanel. <br>Supported types: <ul> <li>
-   * PowerDistributionPanel</li>
+   * Displays a PowerDistribution. <br>Supported types: <ul> <li>
+   * PowerDistribution</li>
    * </ul>
    * <br>Custom properties:
    * <table>
@@ -173,7 +170,7 @@
    * <td>Whether or not to display the voltage and current draw</td></tr>
    * </table>
    */
-  kPowerDistributionPanel,
+  kPowerDistribution,
   /**
    * Displays a SendableChooser with a dropdown combo box with a list of
    * options.
@@ -203,10 +200,10 @@
    */
   kEncoder,
   /**
-   * Displays a SpeedController.
-   * The speed controller will be controllable from the dashboard when test mode
+   * Displays a 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>PWMSpeedController</li>
+   * <li>PWMMotorController</li>
    * <li>DMC60</li>
    * <li>Jaguar</li>
    * <li>PWMTalonSRX</li>
@@ -216,7 +213,7 @@
    * <li>Talon</li>
    * <li>Victor</li>
    * <li>VictorSP</li>
-   * <li>SpeedControllerGroup</li>
+   * <li>MotorControllerGroup</li>
    * <li>Any custom subclass of {@code SpeedContorller}</li>
    * </ul>
    * <br>Custom properties:
@@ -226,7 +223,7 @@
    * <td>One of {@code ["HORIZONTAL", "VERTICAL"]}</td></tr>
    * </table>
    */
-  kSpeedController,
+  kMotorController,
   /**
    * Displays a command with a toggle button. Pressing the button will start the
    * command, and the button will automatically release when the command
@@ -283,7 +280,7 @@
    * <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
+   * <tr><td>Range</td><td>Range</td><td>k16G</td><td>The accelerometer
    * range</td></tr> <tr><td>Show value</td><td>Boolean</td><td>true</td>
    * <td>Show or hide the acceleration values</td></tr>
    * <tr><td>Precision</td><td>Number</td><td>2</td>
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ComplexWidget.h b/wpilibc/src/main/native/include/frc/shuffleboard/ComplexWidget.h
index 218ed2f..dc49d64 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ComplexWidget.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ComplexWidget.h
@@ -1,34 +1,35 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
-#include <wpi/Twine.h>
 
 #include "frc/shuffleboard/ShuffleboardWidget.h"
-#include "frc/smartdashboard/SendableBuilder.h"
-#include "frc/smartdashboard/SendableBuilderImpl.h"
+
+namespace wpi {
+class Sendable;
+class SendableBuilder;
+}  // namespace wpi
 
 namespace frc {
 
-class Sendable;
 class ShuffleboardContainer;
 
 /**
- * A Shuffleboard widget that handles a {@link Sendable} object such as a speed
+ * A Shuffleboard widget that handles a Sendable object such as a speed
  * controller or sensor.
  */
 class ComplexWidget final : public ShuffleboardWidget<ComplexWidget> {
  public:
-  ComplexWidget(ShuffleboardContainer& parent, const wpi::Twine& title,
-                Sendable& sendable);
+  ComplexWidget(ShuffleboardContainer& parent, std::string_view title,
+                wpi::Sendable& sendable);
+
+  ~ComplexWidget() override;
 
   void EnableIfActuator() override;
 
@@ -38,9 +39,8 @@
                  std::shared_ptr<nt::NetworkTable> metaTable) override;
 
  private:
-  Sendable& m_sendable;
-  SendableBuilderImpl m_builder;
-  bool m_builderInit = false;
+  wpi::Sendable& m_sendable;
+  std::unique_ptr<wpi::SendableBuilder> m_builder;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/LayoutType.h b/wpilibc/src/main/native/include/frc/shuffleboard/LayoutType.h
index 00a5e36..5fa5ca4 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/LayoutType.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/LayoutType.h
@@ -1,13 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/StringRef.h>
+#include <string_view>
 
 namespace frc {
 
@@ -28,7 +25,7 @@
    * Gets the string type of the layout as defined by that layout in
    * Shuffleboard.
    */
-  wpi::StringRef GetLayoutName() const;
+  std::string_view GetLayoutName() const;
 
  private:
   const char* m_layoutName;
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/RecordingController.h b/wpilibc/src/main/native/include/frc/shuffleboard/RecordingController.h
index dacbdb4..83b23a4 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/RecordingController.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/RecordingController.h
@@ -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.
 
 #pragma once
 
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
 #include <networktables/NetworkTableInstance.h>
 #include <wpi/SmallVector.h>
-#include <wpi/StringRef.h>
 
 #include "frc/shuffleboard/ShuffleboardEventImportance.h"
 
-namespace frc {
-namespace detail {
+namespace frc::detail {
 
 class RecordingController final {
  public:
@@ -27,10 +23,10 @@
 
   void StartRecording();
   void StopRecording();
-  void SetRecordingFileNameFormat(wpi::StringRef format);
+  void SetRecordingFileNameFormat(std::string_view format);
   void ClearRecordingFileNameFormat();
 
-  void AddEventMarker(wpi::StringRef name, wpi::StringRef description,
+  void AddEventMarker(std::string_view name, std::string_view description,
                       ShuffleboardEventImportance importance);
 
  private:
@@ -39,5 +35,4 @@
   std::shared_ptr<nt::NetworkTable> m_eventsTable;
 };
 
-}  // namespace detail
-}  // namespace frc
+}  // namespace frc::detail
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/SendableCameraWrapper.h b/wpilibc/src/main/native/include/frc/shuffleboard/SendableCameraWrapper.h
index 5610cf8..e7c9a81 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/SendableCameraWrapper.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/SendableCameraWrapper.h
@@ -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.
 
 #pragma once
 
@@ -17,12 +14,12 @@
 namespace cs {
 class VideoSource;
 }  // namespace cs
-typedef int CS_Handle;
-typedef CS_Handle CS_Source;
+using CS_Handle = int;        // NOLINT
+using CS_Source = CS_Handle;  // NOLINT
 #endif
 
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <wpi/sendable/Sendable.h>
+#include <wpi/sendable/SendableHelper.h>
 
 namespace frc {
 
@@ -32,14 +29,15 @@
 constexpr const char* kProtocol = "camera_server://";
 std::shared_ptr<SendableCameraWrapper>& GetSendableCameraWrapper(
     CS_Source source);
-void AddToSendableRegistry(Sendable* sendable, std::string name);
+void AddToSendableRegistry(wpi::Sendable* sendable, std::string name);
 }  // namespace detail
 
 /**
  * A wrapper to make video sources sendable and usable from Shuffleboard.
  */
-class SendableCameraWrapper : public Sendable,
-                              public SendableHelper<SendableCameraWrapper> {
+class SendableCameraWrapper
+    : public wpi::Sendable,
+      public wpi::SendableHelper<SendableCameraWrapper> {
  private:
   struct private_init {};
 
@@ -63,7 +61,7 @@
   static SendableCameraWrapper& Wrap(const cs::VideoSource& source);
   static SendableCameraWrapper& Wrap(CS_Source source);
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(wpi::SendableBuilder& builder) override;
 
  private:
   std::string m_uri;
@@ -86,8 +84,9 @@
 
 inline SendableCameraWrapper& SendableCameraWrapper::Wrap(CS_Source source) {
   auto& wrapper = detail::GetSendableCameraWrapper(source);
-  if (!wrapper)
+  if (!wrapper) {
     wrapper = std::make_shared<SendableCameraWrapper>(source, private_init{});
+  }
   return *wrapper;
 }
 #endif
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/Shuffleboard.h b/wpilibc/src/main/native/include/frc/shuffleboard/Shuffleboard.h
index e49d1c3..252d74a 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/Shuffleboard.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/Shuffleboard.h
@@ -1,13 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/StringRef.h>
+#include <string_view>
 
 #include "frc/shuffleboard/RecordingController.h"
 #include "frc/shuffleboard/ShuffleboardEventImportance.h"
@@ -80,7 +77,7 @@
    * @param title the title of the tab
    * @return the tab with the given title
    */
-  static ShuffleboardTab& GetTab(wpi::StringRef title);
+  static ShuffleboardTab& GetTab(std::string_view title);
 
   /**
    * Selects the tab in the dashboard with the given index in the range
@@ -96,10 +93,10 @@
    *
    * @param title the title of the tab to select
    */
-  static void SelectTab(wpi::StringRef title);
+  static void SelectTab(std::string_view title);
 
   /**
-   * Enables user control of widgets containing actuators: speed controllers,
+   * 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
@@ -144,13 +141,13 @@
    *
    * @param format the format for the
    */
-  static void SetRecordingFileNameFormat(wpi::StringRef format);
+  static void SetRecordingFileNameFormat(std::string_view format);
 
   /**
    * Clears the custom name format for recording files. New recordings will use
    * the default format.
    *
-   * @see #setRecordingFileNameFormat(String)
+   * @see SetRecordingFileNameFormat(std::string_view)
    */
   static void ClearRecordingFileNameFormat();
 
@@ -166,7 +163,8 @@
    * @param description a description of the event
    * @param importance  the importance of the event
    */
-  static void AddEventMarker(wpi::StringRef name, wpi::StringRef description,
+  static void AddEventMarker(std::string_view name,
+                             std::string_view description,
                              ShuffleboardEventImportance importance);
 
   /**
@@ -180,7 +178,7 @@
    * @param name        the name of the event
    * @param importance  the importance of the event
    */
-  static void AddEventMarker(wpi::StringRef name,
+  static void AddEventMarker(std::string_view name,
                              ShuffleboardEventImportance importance);
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponent.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponent.h
index d6b4bc4..24f65a3 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponent.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponent.h
@@ -1,19 +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.
 
 #pragma once
 
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
 #include <networktables/NetworkTableValue.h>
 #include <wpi/StringMap.h>
-#include <wpi/Twine.h>
 
 #include "frc/shuffleboard/ShuffleboardComponentBase.h"
 
@@ -29,10 +26,8 @@
 template <typename Derived>
 class ShuffleboardComponent : public ShuffleboardComponentBase {
  public:
-  ShuffleboardComponent(ShuffleboardContainer& parent, const wpi::Twine& title,
-                        const wpi::Twine& type = "");
-
-  virtual ~ShuffleboardComponent() = default;
+  ShuffleboardComponent(ShuffleboardContainer& parent, std::string_view title,
+                        std::string_view type = "");
 
   /**
    * Sets custom properties for this component. Property names are
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponent.inc b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponent.inc
index f75fb0d..9750d4a 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponent.inc
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponent.inc
@@ -1,21 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
 #include <string>
+#include <string_view>
+
+#include "frc/shuffleboard/ShuffleboardComponent.h"
 
 namespace frc {
 
 template <typename Derived>
 ShuffleboardComponent<Derived>::ShuffleboardComponent(
-    ShuffleboardContainer& parent, const wpi::Twine& title,
-    const wpi::Twine& type)
+    ShuffleboardContainer& parent, std::string_view title,
+    std::string_view type)
     : ShuffleboardValue(title),
       ShuffleboardComponentBase(parent, title, type) {}
 
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponentBase.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponentBase.h
index c63e517..d33a234 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponentBase.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardComponentBase.h
@@ -1,19 +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.
 
 #pragma once
 
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
 #include <networktables/NetworkTableValue.h>
 #include <wpi/StringMap.h>
-#include <wpi/Twine.h>
 
 #include "frc/shuffleboard/ShuffleboardValue.h"
 
@@ -27,12 +24,9 @@
 class ShuffleboardComponentBase : public virtual ShuffleboardValue {
  public:
   ShuffleboardComponentBase(ShuffleboardContainer& parent,
-                            const wpi::Twine& title,
-                            const wpi::Twine& type = "");
+                            std::string_view title, std::string_view type = "");
 
-  virtual ~ShuffleboardComponentBase() = default;
-
-  void SetType(const wpi::Twine& type);
+  void SetType(std::string_view type);
 
   void BuildMetadata(std::shared_ptr<nt::NetworkTable> metaTable);
 
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardContainer.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardContainer.h
index 7b8b49d..db58a21 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardContainer.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardContainer.h
@@ -1,26 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <functional>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include <networktables/NetworkTableEntry.h>
 #include <networktables/NetworkTableValue.h>
-#include <wpi/ArrayRef.h>
 #include <wpi/SmallSet.h>
 #include <wpi/StringMap.h>
-#include <wpi/Twine.h>
+#include <wpi/span.h>
 
-#include "frc/ErrorBase.h"
-#include "frc/WPIErrors.h"
 #include "frc/shuffleboard/BuiltInLayouts.h"
 #include "frc/shuffleboard/LayoutType.h"
 #include "frc/shuffleboard/ShuffleboardComponentBase.h"
@@ -31,24 +26,26 @@
 class VideoSource;
 }  // namespace cs
 
+namespace wpi {
+class Sendable;
+}  // namespace wpi
+
 namespace frc {
 
 class ComplexWidget;
-class Sendable;
 class ShuffleboardLayout;
 class SimpleWidget;
 
 /**
  * Common interface for objects that can contain shuffleboard components.
  */
-class ShuffleboardContainer : public virtual ShuffleboardValue,
-                              public ErrorBase {
+class ShuffleboardContainer : public virtual ShuffleboardValue {
  public:
-  explicit ShuffleboardContainer(const wpi::Twine& title);
+  explicit ShuffleboardContainer(std::string_view title);
 
   ShuffleboardContainer(ShuffleboardContainer&& rhs) = default;
 
-  virtual ~ShuffleboardContainer() = default;
+  ~ShuffleboardContainer() override = default;
 
   /**
    * Gets the components that are direct children of this container.
@@ -60,38 +57,36 @@
    * 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 layoutType the type of the layout, eg "List" or "Grid"
+   * @param title the title of the layout
+   * @param type  the type of the layout, eg "List" or "Grid"
    * @return the layout
    */
-  ShuffleboardLayout& GetLayout(const wpi::Twine& title, BuiltInLayouts type);
+  ShuffleboardLayout& GetLayout(std::string_view title, BuiltInLayouts type);
 
   /**
    * 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 layoutType the type of the layout, eg "List" or "Grid"
+   * @param title the title of the layout
+   * @param type  the type of the layout, eg "List" or "Grid"
    * @return the layout
    */
-  ShuffleboardLayout& GetLayout(const wpi::Twine& title,
-                                const LayoutType& type);
+  ShuffleboardLayout& GetLayout(std::string_view title, const LayoutType& type);
 
   /**
    * 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}.
+   * GetLayout(std::string_view, const LayoutType&) and the layouts in
+   * BuiltInLayouts.
    *
    * @param title the title of the layout
    * @param type  the type of the layout, eg "List Layout" or "Grid Layout"
    * @return the layout
-   * @see #GetLayout(String, LayoutType)
+   * @see GetLayout(std::string_view, const LayoutType&)
    */
-  ShuffleboardLayout& GetLayout(const wpi::Twine& title,
-                                const wpi::Twine& type);
+  ShuffleboardLayout& GetLayout(std::string_view title, std::string_view type);
 
   /**
    * Gets the already-defined layout in this container with the given title.
@@ -108,7 +103,7 @@
    * @return the layout with the given title
    * @throws if no layout has yet been defined with the given title
    */
-  ShuffleboardLayout& GetLayout(const wpi::Twine& title);
+  ShuffleboardLayout& GetLayout(std::string_view title);
 
   /**
    * Adds a widget to this container to display the given sendable.
@@ -119,7 +114,7 @@
    * @throws IllegalArgumentException if a widget already exists in this
    * container with the given title
    */
-  ComplexWidget& Add(const wpi::Twine& title, Sendable& sendable);
+  ComplexWidget& Add(std::string_view title, wpi::Sendable& sendable);
 
   /**
    * Adds a widget to this container to display the given video stream.
@@ -130,7 +125,7 @@
    * @throws IllegalArgumentException if a widget already exists in this
    * container with the given title
    */
-  ComplexWidget& Add(const wpi::Twine& title, const cs::VideoSource& video);
+  ComplexWidget& Add(std::string_view title, const cs::VideoSource& video);
 
   /**
    * Adds a widget to this container to display the given sendable.
@@ -141,7 +136,7 @@
    * container with the given title, or if the sendable's name has not been
    * specified
    */
-  ComplexWidget& Add(Sendable& sendable);
+  ComplexWidget& Add(wpi::Sendable& sendable);
 
   /**
    * Adds a widget to this container to display the given video stream.
@@ -161,9 +156,10 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, std::shared_ptr<nt::Value>)
+   *      Add(std::string_view title, std::shared_ptr<nt::Value> defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title,
+  SimpleWidget& Add(std::string_view title,
                     std::shared_ptr<nt::Value> defaultValue);
 
   /**
@@ -174,9 +170,10 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, bool)
+   *      Add(std::string_view title, bool defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title, bool defaultValue);
+  SimpleWidget& Add(std::string_view title, bool defaultValue);
 
   /**
    * Adds a widget to this container to display the given data.
@@ -186,9 +183,10 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, double)
+   *      Add(std::string_view title, double defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title, double defaultValue);
+  SimpleWidget& Add(std::string_view title, double defaultValue);
 
   /**
    * Adds a widget to this container to display the given data.
@@ -198,9 +196,10 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, int)
+   *      Add(std::string_view title, int defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title, int defaultValue);
+  SimpleWidget& Add(std::string_view title, int defaultValue);
 
   /**
    * Adds a widget to this container to display the given data.
@@ -210,9 +209,10 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, std::string_view)
+   *      Add(std::string_view title, std::string_view defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title, const wpi::Twine& defaultValue);
+  SimpleWidget& Add(std::string_view title, std::string_view defaultValue);
 
   /**
    * Adds a widget to this container to display the given data.
@@ -222,9 +222,10 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, const char*)
+   *      Add(std::string_view title, const char* defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title, const char* defaultValue);
+  SimpleWidget& Add(std::string_view title, const char* defaultValue);
 
   /**
    * Adds a widget to this container to display the given data.
@@ -234,9 +235,10 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, wpi::span<const bool>)
+   *      Add(std::string_view title, wpi::span<const bool> defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title, wpi::ArrayRef<bool> defaultValue);
+  SimpleWidget& Add(std::string_view title, wpi::span<const bool> defaultValue);
 
   /**
    * Adds a widget to this container to display the given data.
@@ -246,10 +248,11 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, wpi::span<const double>)
+   *      Add(std::string_view title, wpi::span<const double> defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title,
-                    wpi::ArrayRef<double> defaultValue);
+  SimpleWidget& Add(std::string_view title,
+                    wpi::span<const double> defaultValue);
 
   /**
    * Adds a widget to this container to display the given data.
@@ -259,10 +262,11 @@
    * @return a widget to display the sendable data
    * @throws IllegalArgumentException if a widget already exists in this
    *         container with the given title
-   * @see #addPersistent(String, Object) add(String title, Object defaultValue)
+   * @see AddPersistent(std::string_view, wpi::span<const std::string>)
+   *      Add(std::string_view title, wpi::span<const std::string> defaultValue)
    */
-  SimpleWidget& Add(const wpi::Twine& title,
-                    wpi::ArrayRef<std::string> defaultValue);
+  SimpleWidget& Add(std::string_view title,
+                    wpi::span<const std::string> defaultValue);
 
   /**
    * Adds a widget to this container. The widget will display the data provided
@@ -271,11 +275,11 @@
    * supplier.
    *
    * @param title the title of the widget
-   * @param valueSupplier the supplier for values
+   * @param supplier the supplier for values
    * @return a widget to display data
    */
   SuppliedValueWidget<std::string>& AddString(
-      const wpi::Twine& title, std::function<std::string()> supplier);
+      std::string_view title, std::function<std::string()> supplier);
 
   /**
    * Adds a widget to this container. The widget will display the data provided
@@ -284,10 +288,10 @@
    * supplier.
    *
    * @param title the title of the widget
-   * @param valueSupplier the supplier for values
+   * @param supplier the supplier for values
    * @return a widget to display data
    */
-  SuppliedValueWidget<double>& AddNumber(const wpi::Twine& title,
+  SuppliedValueWidget<double>& AddNumber(std::string_view title,
                                          std::function<double()> supplier);
 
   /**
@@ -297,10 +301,10 @@
    * supplier.
    *
    * @param title the title of the widget
-   * @param valueSupplier the supplier for values
+   * @param supplier the supplier for values
    * @return a widget to display data
    */
-  SuppliedValueWidget<bool>& AddBoolean(const wpi::Twine& title,
+  SuppliedValueWidget<bool>& AddBoolean(std::string_view title,
                                         std::function<bool()> supplier);
 
   /**
@@ -310,11 +314,11 @@
    * supplier.
    *
    * @param title the title of the widget
-   * @param valueSupplier the supplier for values
+   * @param supplier the supplier for values
    * @return a widget to display data
    */
   SuppliedValueWidget<std::vector<std::string>>& AddStringArray(
-      const wpi::Twine& title,
+      std::string_view title,
       std::function<std::vector<std::string>()> supplier);
 
   /**
@@ -324,11 +328,11 @@
    * supplier.
    *
    * @param title the title of the widget
-   * @param valueSupplier the supplier for values
+   * @param supplier the supplier for values
    * @return a widget to display data
    */
   SuppliedValueWidget<std::vector<double>>& AddNumberArray(
-      const wpi::Twine& title, std::function<std::vector<double>()> supplier);
+      std::string_view title, std::function<std::vector<double>()> supplier);
 
   /**
    * Adds a widget to this container. The widget will display the data provided
@@ -337,11 +341,11 @@
    * supplier.
    *
    * @param title the title of the widget
-   * @param valueSupplier the supplier for values
+   * @param supplier the supplier for values
    * @return a widget to display data
    */
   SuppliedValueWidget<std::vector<int>>& AddBooleanArray(
-      const wpi::Twine& title, std::function<std::vector<int>()> supplier);
+      std::string_view title, std::function<std::vector<int>()> supplier);
 
   /**
    * Adds a widget to this container. The widget will display the data provided
@@ -350,128 +354,136 @@
    * supplier.
    *
    * @param title the title of the widget
-   * @param valueSupplier the supplier for values
+   * @param supplier the supplier for values
    * @return a widget to display data
    */
-  SuppliedValueWidget<wpi::StringRef>& AddRaw(
-      const wpi::Twine& title, std::function<wpi::StringRef()> supplier);
+  SuppliedValueWidget<std::string_view>& AddRaw(
+      std::string_view title, std::function<std::string_view()> supplier);
 
   /**
    * 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}.
+   * Unlike Add(std::string_view, std::shared_ptr<nt::Value>), 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 defaultValue the default value of the widget
    * @return a widget to display the sendable data
-   * @see #add(String, Object) add(String title, Object defaultValue)
+   * @see Add(stdd::string_view, std::shared_ptr<nt::Value>)
+   *      Add(std::string_view title, std::shared_ptr<nt::Value> defaultValue)
    */
-  SimpleWidget& AddPersistent(const wpi::Twine& title,
+  SimpleWidget& AddPersistent(std::string_view title,
                               std::shared_ptr<nt::Value> 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
+   * Unlike Add(std::string_view, bool), 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 defaultValue the default value of the widget
    * @return a widget to display the sendable data
-   * @see #add(String, Object) add(String title, Object defaultValue)
+   * @see Add(std::string_view, bool)
+   *      Add(std::string_view title, bool defaultValue)
    */
-  SimpleWidget& AddPersistent(const wpi::Twine& title, bool defaultValue);
+  SimpleWidget& AddPersistent(std::string_view title, bool 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
+   * Unlike Add(std::string_view, double), 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 defaultValue the default value of the widget
    * @return a widget to display the sendable data
-   * @see #add(String, Object) add(String title, Object defaultValue)
+   * @see Add(std::string_view, double)
+   *      Add(std::string_view title, double defaultValue)
    */
-  SimpleWidget& AddPersistent(const wpi::Twine& title, double defaultValue);
+  SimpleWidget& AddPersistent(std::string_view title, double 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}.
+   * Unlike Add(std::string_view, int), 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 defaultValue the default value of the widget
    * @return a widget to display the sendable data
-   * @see #add(String, Object) add(String title, Object defaultValue)
+   * @see Add(std:string_view, int)
+   *      Add(std::string_view title, int defaultValue)
    */
-  SimpleWidget& AddPersistent(const wpi::Twine& title, int defaultValue);
+  SimpleWidget& AddPersistent(std::string_view title, int 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}.
+   * Unlike Add(std::string_view, std::string_view), 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 defaultValue the default value of the widget
    * @return a widget to display the sendable data
-   * @see #add(String, Object) add(String title, Object defaultValue)
+   * @see Add(std::string_view, std::string_view)
+   *      Add(std::string_view title, std::string_view defaultValue)
    */
-  SimpleWidget& AddPersistent(const wpi::Twine& title,
-                              const wpi::Twine& defaultValue);
+  SimpleWidget& AddPersistent(std::string_view title,
+                              std::string_view 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}.
+   * Unlike Add(std::string_view, wpi::span<const bool>), 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 defaultValue the default value of the widget
    * @return a widget to display the sendable data
-   * @see #add(String, Object) add(String title, Object defaultValue)
+   * @see Add(std::string_view, wpi::span<const bool>)
+   *      Add(std::string_view title, wpi::span<const bool> defaultValue)
    */
-  SimpleWidget& AddPersistent(const wpi::Twine& title,
-                              wpi::ArrayRef<bool> defaultValue);
+  SimpleWidget& AddPersistent(std::string_view title,
+                              wpi::span<const bool> 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}.
+   * Unlike Add(std::string_view, wpi::span<const double>), 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 defaultValue the default value of the widget
    * @return a widget to display the sendable data
-   * @see #add(String, Object) add(String title, Object defaultValue)
+   * @see Add(std::string_view, wpi::span<const double>)
+   *      Add(std::string_view title, wpi::span<const double> defaultValue)
    */
-  SimpleWidget& AddPersistent(const wpi::Twine& title,
-                              wpi::ArrayRef<double> defaultValue);
+  SimpleWidget& AddPersistent(std::string_view title,
+                              wpi::span<const double> 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}.
+   * Unlike Add(std::string_view, wpi::span<const std::string>), 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 defaultValue the default value of the widget
    * @return a widget to display the sendable data
-   * @see #add(String, Object) add(String title, Object defaultValue)
+   * @see Add(std::string_view, wpi::span<const std::string>)
+   *      Add(std::string_view title, wpi::span<const std::string> defaultValue)
    */
-  SimpleWidget& AddPersistent(const wpi::Twine& title,
-                              wpi::ArrayRef<std::string> defaultValue);
+  SimpleWidget& AddPersistent(std::string_view title,
+                              wpi::span<const std::string> defaultValue);
 
   void EnableIfActuator() override;
 
@@ -490,7 +502,7 @@
    *
    * @return True if title isn't in use; false otherwise.
    */
-  void CheckTitle(const wpi::Twine& title);
+  void CheckTitle(std::string_view title);
 
   friend class SimpleWidget;
 };
@@ -511,7 +523,7 @@
 }
 
 inline frc::ComplexWidget& frc::ShuffleboardContainer::Add(
-    const wpi::Twine& title, const cs::VideoSource& video) {
+    std::string_view title, const cs::VideoSource& video) {
   return Add(title, frc::SendableCameraWrapper::Wrap(video));
 }
 #endif
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardEventImportance.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardEventImportance.h
index 57e4743..1fa9c91 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardEventImportance.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardEventImportance.h
@@ -1,13 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/StringRef.h>
+#include <string_view>
 
 namespace frc {
 
@@ -17,7 +14,7 @@
 
 enum ShuffleboardEventImportance { kTrivial, kLow, kNormal, kHigh, kCritical };
 
-inline wpi::StringRef ShuffleboardEventImportanceName(
+inline std::string_view ShuffleboardEventImportanceName(
     ShuffleboardEventImportance importance) {
   switch (importance) {
     case kTrivial:
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardInstance.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardInstance.h
index 2be9859..2885af7 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardInstance.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardInstance.h
@@ -1,19 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
+#include <string_view>
 
 #include "frc/shuffleboard/ShuffleboardRoot.h"
 #include "frc/shuffleboard/ShuffleboardTab.h"
 
-namespace frc {
-namespace detail {
+namespace frc::detail {
 
 class ShuffleboardInstance final : public ShuffleboardRoot {
  public:
@@ -23,7 +20,7 @@
   ShuffleboardInstance(ShuffleboardInstance&&) = default;
   ShuffleboardInstance& operator=(ShuffleboardInstance&&) = default;
 
-  frc::ShuffleboardTab& GetTab(wpi::StringRef title) override;
+  frc::ShuffleboardTab& GetTab(std::string_view title) override;
 
   void Update() override;
 
@@ -33,12 +30,11 @@
 
   void SelectTab(int index) override;
 
-  void SelectTab(wpi::StringRef) override;
+  void SelectTab(std::string_view) override;
 
  private:
   struct Impl;
   std::unique_ptr<Impl> m_impl;
 };
 
-}  // namespace detail
-}  // namespace frc
+}  // namespace frc::detail
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardLayout.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardLayout.h
index effa3da..fe9e102 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardLayout.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardLayout.h
@@ -1,16 +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.
 
 #pragma once
 
 #include <memory>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
-#include <wpi/Twine.h>
 
 #include "frc/shuffleboard/ShuffleboardComponent.h"
 #include "frc/shuffleboard/ShuffleboardContainer.h"
@@ -29,8 +26,8 @@
 class ShuffleboardLayout : public ShuffleboardComponent<ShuffleboardLayout>,
                            public ShuffleboardContainer {
  public:
-  ShuffleboardLayout(ShuffleboardContainer& parent, const wpi::Twine& name,
-                     const wpi::Twine& type);
+  ShuffleboardLayout(ShuffleboardContainer& parent, std::string_view name,
+                     std::string_view type);
 
   void BuildInto(std::shared_ptr<nt::NetworkTable> parentTable,
                  std::shared_ptr<nt::NetworkTable> metaTable) override;
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardRoot.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardRoot.h
index 0c50545..1e766a8 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardRoot.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardRoot.h
@@ -1,13 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/StringRef.h>
+#include <string_view>
 
 namespace frc {
 
@@ -28,7 +25,7 @@
    * @param title the title of the tab
    * @return the tab with the given title
    */
-  virtual ShuffleboardTab& GetTab(wpi::StringRef title) = 0;
+  virtual ShuffleboardTab& GetTab(std::string_view title) = 0;
 
   /**
    * Updates all tabs.
@@ -60,7 +57,7 @@
    *
    * @param title the title of the tab to select
    */
-  virtual void SelectTab(wpi::StringRef title) = 0;
+  virtual void SelectTab(std::string_view title) = 0;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardTab.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardTab.h
index 75896ae..8864cdb 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardTab.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardTab.h
@@ -1,16 +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.
 
 #pragma once
 
 #include <memory>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
-#include <wpi/StringRef.h>
 
 #include "frc/shuffleboard/ShuffleboardContainer.h"
 
@@ -20,14 +17,15 @@
 
 /**
  * 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).
+ * tab with Add(Sendable), Add(std::string_view, Object), and
+ * Add(String, Sendable). Widgets can also be added to layouts with
+ * GetLayout(std::string_view, std::string_view); layouts can be nested
+ * arbitrarily deep (note that too many levels may make deeper components
+ * unusable).
  */
 class ShuffleboardTab final : public ShuffleboardContainer {
  public:
-  ShuffleboardTab(ShuffleboardRoot& root, wpi::StringRef title);
+  ShuffleboardTab(ShuffleboardRoot& root, std::string_view title);
 
   ShuffleboardRoot& GetRoot();
 
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardValue.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardValue.h
index 4a88cc1..4b7ccd4 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardValue.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardValue.h
@@ -1,34 +1,30 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
-#include <wpi/SmallVector.h>
-#include <wpi/StringRef.h>
 
 namespace frc {
 
 class ShuffleboardValue {
  public:
-  explicit ShuffleboardValue(const wpi::Twine& title) {
-    wpi::SmallVector<char, 16> storage;
-    m_title = title.toStringRef(storage);
-  }
+  explicit ShuffleboardValue(std::string_view title) : m_title(title) {}
 
   virtual ~ShuffleboardValue() = default;
 
+  ShuffleboardValue(const ShuffleboardValue&) = delete;
+  ShuffleboardValue& operator=(const ShuffleboardValue&) = delete;
+
   /**
    * Gets the title of this Shuffleboard value.
    */
-  wpi::StringRef GetTitle() const { return m_title; }
+  const std::string& GetTitle() const { return m_title; }
 
   /**
    * Builds the entries for this value.
@@ -51,7 +47,7 @@
    *
    * This method is package-private to prevent users from enabling control
    * themselves. Has no effect if the sendable is not marked as an actuator with
-   * {@link SendableBuilder#setActuator}.
+   * SendableBuilder::SetActuator().
    */
   virtual void EnableIfActuator() {}
 
@@ -60,7 +56,7 @@
    *
    * This method is package-private to prevent users from enabling control
    * themselves. Has no effect if the sendable is not marked as an actuator with
-   * {@link SendableBuilder#setActuator}.
+   * SendableBuilder::SetActuator().
    */
   virtual void DisableIfActuator() {}
 
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardWidget.h b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardWidget.h
index 729da40..ce01367 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardWidget.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/ShuffleboardWidget.h
@@ -1,13 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/Twine.h>
+#include <string_view>
 
 #include "frc/shuffleboard/BuiltInWidgets.h"
 #include "frc/shuffleboard/ShuffleboardComponent.h"
@@ -31,7 +28,7 @@
 template <typename Derived>
 class ShuffleboardWidget : public ShuffleboardComponent<Derived> {
  public:
-  ShuffleboardWidget(ShuffleboardContainer& parent, const wpi::Twine& title)
+  ShuffleboardWidget(ShuffleboardContainer& parent, std::string_view title)
       : ShuffleboardValue(title),
         ShuffleboardComponent<Derived>(parent, title) {}
 
@@ -63,13 +60,12 @@
    * 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, use WithWidget(WidgetType) and BuiltInWidgets.
    *
    * @param widgetType the type of the widget used to display the data
    * @return this widget object
    */
-  Derived& WithWidget(const wpi::Twine& widgetType) {
+  Derived& WithWidget(std::string_view widgetType) {
     this->SetType(widgetType);
     return *static_cast<Derived*>(this);
   }
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/SimpleWidget.h b/wpilibc/src/main/native/include/frc/shuffleboard/SimpleWidget.h
index 973f8cb..746b7d6 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/SimpleWidget.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/SimpleWidget.h
@@ -1,17 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <memory>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
 #include <networktables/NetworkTableEntry.h>
-#include <wpi/Twine.h>
 
 #include "frc/shuffleboard/ShuffleboardWidget.h"
 
@@ -25,7 +22,7 @@
  */
 class SimpleWidget final : public ShuffleboardWidget<SimpleWidget> {
  public:
-  SimpleWidget(ShuffleboardContainer& parent, const wpi::Twine& title);
+  SimpleWidget(ShuffleboardContainer& parent, std::string_view title);
 
   /**
    * Gets the NetworkTable entry that contains the data for this widget.
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/SuppliedValueWidget.h b/wpilibc/src/main/native/include/frc/shuffleboard/SuppliedValueWidget.h
index c806db4..a2b042e 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/SuppliedValueWidget.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/SuppliedValueWidget.h
@@ -1,34 +1,32 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <functional>
 #include <memory>
+#include <string_view>
 
 #include <networktables/NetworkTable.h>
 #include <networktables/NetworkTableEntry.h>
-#include <wpi/Twine.h>
 
 #include "frc/shuffleboard/ShuffleboardComponent.h"
 #include "frc/shuffleboard/ShuffleboardComponent.inc"
 #include "frc/shuffleboard/ShuffleboardComponentBase.h"
-#include "frc/shuffleboard/ShuffleboardContainer.h"
 #include "frc/shuffleboard/ShuffleboardWidget.h"
 
 namespace frc {
+class ShuffleboardContainer;
+
 template <typename T>
-class SuppliedValueWidget : public ShuffleboardWidget<SuppliedValueWidget<T> > {
+class SuppliedValueWidget : public ShuffleboardWidget<SuppliedValueWidget<T>> {
  public:
-  SuppliedValueWidget(ShuffleboardContainer& parent, const wpi::Twine& title,
+  SuppliedValueWidget(ShuffleboardContainer& parent, std::string_view title,
                       std::function<T()> supplier,
                       std::function<void(nt::NetworkTableEntry, T)> setter)
       : ShuffleboardValue(title),
-        ShuffleboardWidget<SuppliedValueWidget<T> >(parent, title),
+        ShuffleboardWidget<SuppliedValueWidget<T>>(parent, title),
         m_supplier(supplier),
         m_setter(setter) {}
 
diff --git a/wpilibc/src/main/native/include/frc/shuffleboard/WidgetType.h b/wpilibc/src/main/native/include/frc/shuffleboard/WidgetType.h
index ff92fe7..13805bb 100644
--- a/wpilibc/src/main/native/include/frc/shuffleboard/WidgetType.h
+++ b/wpilibc/src/main/native/include/frc/shuffleboard/WidgetType.h
@@ -1,13 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
-#include <wpi/StringRef.h>
+#include <string_view>
 
 namespace frc {
 
@@ -28,7 +25,7 @@
    * Gets the string type of the widget as defined by that widget in
    * Shuffleboard.
    */
-  wpi::StringRef GetWidgetName() const;
+  std::string_view GetWidgetName() const;
 
  private:
   const char* m_widgetName;
diff --git a/wpilibc/src/main/native/include/frc/simulation/ADXL345Sim.h b/wpilibc/src/main/native/include/frc/simulation/ADXL345Sim.h
new file mode 100644
index 0000000..af96b39
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/simulation/ADXL345Sim.h
@@ -0,0 +1,63 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <hal/SimDevice.h>
+
+namespace frc {
+
+class ADXL345_SPI;
+class ADXL345_I2C;
+
+namespace sim {
+
+/**
+ * Class to control a simulated ADXRS450 gyroscope.
+ */
+class ADXL345Sim {
+ public:
+  /**
+   * Constructs from a ADXL345_I2C object.
+   *
+   * @param accel ADXL345 accel to simulate
+   */
+  explicit ADXL345Sim(const ADXL345_I2C& accel);
+
+  /**
+   * Constructs from a ADXL345_SPI object.
+   *
+   * @param accel ADXL345 accel to simulate
+   */
+  explicit ADXL345Sim(const ADXL345_SPI& accel);
+
+  /**
+   * Sets the X acceleration.
+   *
+   * @param accel The X acceleration.
+   */
+  void SetX(double accel);
+
+  /**
+   * Sets the Y acceleration.
+   *
+   * @param accel The Y acceleration.
+   */
+  void SetY(double accel);
+
+  /**
+   * Sets the Z acceleration.
+   *
+   * @param accel The Z acceleration.
+   */
+  void SetZ(double accel);
+
+ private:
+  hal::SimDouble m_simX;
+  hal::SimDouble m_simY;
+  hal::SimDouble m_simZ;
+};
+
+}  // namespace sim
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/ADXL362Sim.h b/wpilibc/src/main/native/include/frc/simulation/ADXL362Sim.h
new file mode 100644
index 0000000..269732b
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/simulation/ADXL362Sim.h
@@ -0,0 +1,55 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <hal/SimDevice.h>
+
+namespace frc {
+
+class ADXL362;
+
+namespace sim {
+
+/**
+ * Class to control a simulated ADXRS450 gyroscope.
+ */
+class ADXL362Sim {
+ public:
+  /**
+   * Constructs from a ADXL362 object.
+   *
+   * @param accel ADXL362 accel to simulate
+   */
+  explicit ADXL362Sim(const ADXL362& accel);
+
+  /**
+   * Sets the X acceleration.
+   *
+   * @param accel The X acceleration.
+   */
+  void SetX(double accel);
+
+  /**
+   * Sets the Y acceleration.
+   *
+   * @param accel The Y acceleration.
+   */
+  void SetY(double accel);
+
+  /**
+   * Sets the Z acceleration.
+   *
+   * @param accel The Z acceleration.
+   */
+  void SetZ(double accel);
+
+ private:
+  hal::SimDouble m_simX;
+  hal::SimDouble m_simY;
+  hal::SimDouble m_simZ;
+};
+
+}  // namespace sim
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/ADXRS450_GyroSim.h b/wpilibc/src/main/native/include/frc/simulation/ADXRS450_GyroSim.h
index 1d2d2c3..4cb4737 100644
--- a/wpilibc/src/main/native/include/frc/simulation/ADXRS450_GyroSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/ADXRS450_GyroSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/simulation/AddressableLEDSim.h b/wpilibc/src/main/native/include/frc/simulation/AddressableLEDSim.h
index 0c578f4..4533086 100644
--- a/wpilibc/src/main/native/include/frc/simulation/AddressableLEDSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/AddressableLEDSim.h
@@ -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.
 
 #pragma once
 
@@ -55,39 +52,131 @@
    */
   static AddressableLEDSim CreateForIndex(int index);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object storing this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Change the Initialized value of the LED strip.
+   *
+   * @param initialized the new value
+   */
   void SetInitialized(bool initialized);
 
-  std::unique_ptr<CallbackStore> RegisterOutputPortCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterOutputPortCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the output port.
+   *
+   * @return the output port
+   */
   int GetOutputPort() const;
 
+  /**
+   * Change the output port.
+   *
+   * @param outputPort the new output port
+   */
   void SetOutputPort(int outputPort);
 
-  std::unique_ptr<CallbackStore> RegisterLengthCallback(NotifyCallback callback,
-                                                        bool initialNotify);
-
-  int GetLength() const;
-
-  void SetLength(int length);
-
-  std::unique_ptr<CallbackStore> RegisterRunningCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterLengthCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the length of the LED strip.
+   *
+   * @return the length
+   */
+  int GetLength() const;
+
+  /**
+   * Change the length of the LED strip.
+   *
+   * @param length the new value
+   */
+  void SetLength(int 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterRunningCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check if the LEDs are running.
+   *
+   * @return true if they are
+   */
   int GetRunning() const;
 
+  /**
+   * Change whether the LEDs are active.
+   *
+   * @param running the new value
+   */
   void SetRunning(bool running);
 
-  std::unique_ptr<CallbackStore> RegisterDataCallback(NotifyCallback callback,
-                                                      bool initialNotify);
+  /**
+   * Register a callback on the LED data.
+   *
+   * @param callback the callback that will be called whenever the LED data is
+   *                 changed
+   * @param initialNotify if true, the callback will be run on the initial value
+   * @return the CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterDataCallback(
+      ConstBufferCallback callback, bool initialNotify);
 
+  /**
+   * Get the LED data.
+   *
+   * @param data output parameter to fill with LED data
+   * @return the length of the LED data
+   */
   int GetData(struct HAL_AddressableLEDData* data) const;
 
+  /**
+   * Change the LED data.
+   *
+   * @param data the new data
+   * @param length the length of the LED data
+   */
   void SetData(struct HAL_AddressableLEDData* data, int length);
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/AnalogEncoderSim.h b/wpilibc/src/main/native/include/frc/simulation/AnalogEncoderSim.h
index aef979a..6d76326 100644
--- a/wpilibc/src/main/native/include/frc/simulation/AnalogEncoderSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/AnalogEncoderSim.h
@@ -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.
 
 #pragma once
 
@@ -31,7 +28,7 @@
   explicit AnalogEncoderSim(const AnalogEncoder& encoder);
 
   /**
-   * Set the position using an {@link Rotation2d}.
+   * Set the position using an Rotation2d.
    *
    * @param angle The angle.
    */
@@ -50,7 +47,7 @@
   units::turn_t GetTurns();
 
   /**
-   * Get the position as a {@link Rotation2d}.
+   * Get the position as a Rotation2d.
    */
   Rotation2d GetPosition();
 
diff --git a/wpilibc/src/main/native/include/frc/simulation/AnalogGyroSim.h b/wpilibc/src/main/native/include/frc/simulation/AnalogGyroSim.h
index 685e3ed..faa11d7 100644
--- a/wpilibc/src/main/native/include/frc/simulation/AnalogGyroSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/AnalogGyroSim.h
@@ -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.
 
 #pragma once
 
@@ -36,27 +33,82 @@
    */
   explicit AnalogGyroSim(int channel);
 
-  std::unique_ptr<CallbackStore> RegisterAngleCallback(NotifyCallback callback,
-                                                       bool initialNotify);
-
-  double GetAngle() const;
-
-  void SetAngle(double angle);
-
-  std::unique_ptr<CallbackStore> RegisterRateCallback(NotifyCallback callback,
-                                                      bool initialNotify);
-
-  double GetRate() const;
-
-  void SetRate(double rate);
-
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterAngleCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the current angle of the gyro.
+   *
+   * @return the angle measured by the gyro
+   */
+  double GetAngle() const;
+
+  /**
+   * Change the angle measured by the gyro.
+   *
+   * @param angle the new value
+   */
+  void SetAngle(double 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterRateCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Get the rate of angle change on this gyro.
+   *
+   * @return the rate
+   */
+  double GetRate() const;
+
+  /**
+   * Change the rate of the gyro.
+   *
+   * @param rate the new rate
+   */
+  void SetRate(double 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check if the gyro is initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Set whether this gyro is initialized.
+   *
+   * @param initialized the new value
+   */
   void SetInitialized(bool initialized);
 
+  /**
+   * Reset all simulation data for this object.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/AnalogInputSim.h b/wpilibc/src/main/native/include/frc/simulation/AnalogInputSim.h
index a52cec4..03d7548 100644
--- a/wpilibc/src/main/native/include/frc/simulation/AnalogInputSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/AnalogInputSim.h
@@ -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.
 
 #pragma once
 
@@ -36,69 +33,237 @@
    */
   explicit AnalogInputSim(int channel);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if this analog input has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Change whether this analog input has been initialized.
+   *
+   * @param initialized the new value
+   */
   void SetInitialized(bool initialized);
 
-  std::unique_ptr<CallbackStore> RegisterAverageBitsCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterAverageBitsCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the number of average bits.
+   *
+   * @return the number of average bits
+   */
   int GetAverageBits() const;
 
+  /**
+   * Change the number of average bits.
+   *
+   * @param averageBits the new value
+   */
   void SetAverageBits(int averageBits);
 
-  std::unique_ptr<CallbackStore> RegisterOversampleBitsCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterOversampleBitsCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the amount of oversampling bits.
+   *
+   * @return the amount of oversampling bits
+   */
   int GetOversampleBits() const;
 
+  /**
+   * Change the amount of oversampling bits.
+   *
+   * @param oversampleBits the new value
+   */
   void SetOversampleBits(int oversampleBits);
 
-  std::unique_ptr<CallbackStore> RegisterVoltageCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterVoltageCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the voltage.
+   *
+   * @return the voltage
+   */
   double GetVoltage() const;
 
+  /**
+   * Change the voltage.
+   *
+   * @param voltage the new value
+   */
   void SetVoltage(double voltage);
 
-  std::unique_ptr<CallbackStore> RegisterAccumulatorInitializedCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterAccumulatorInitializedCallback(NotifyCallback callback,
+                                         bool initialNotify);
 
+  /**
+   * Check if the accumulator has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetAccumulatorInitialized() const;
 
+  /**
+   * Change whether the accumulator has been initialized.
+   *
+   * @param accumulatorInitialized the new value
+   */
   void SetAccumulatorInitialized(bool accumulatorInitialized);
 
-  std::unique_ptr<CallbackStore> RegisterAccumulatorValueCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterAccumulatorValueCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the accumulator value.
+   *
+   * @return the accumulator value
+   */
   int64_t GetAccumulatorValue() const;
 
+  /**
+   * Change the accumulator value.
+   *
+   * @param accumulatorValue the new value
+   */
   void SetAccumulatorValue(int64_t accumulatorValue);
 
-  std::unique_ptr<CallbackStore> RegisterAccumulatorCountCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterAccumulatorCountCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the accumulator count.
+   *
+   * @return the accumulator count.
+   */
   int64_t GetAccumulatorCount() const;
 
+  /**
+   * Change the accumulator count.
+   *
+   * @param accumulatorCount the new count.
+   */
   void SetAccumulatorCount(int64_t accumulatorCount);
 
-  std::unique_ptr<CallbackStore> RegisterAccumulatorCenterCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterAccumulatorCenterCallback(NotifyCallback callback,
+                                    bool initialNotify);
 
+  /**
+   * Get the accumulator center.
+   *
+   * @return the accumulator center
+   */
   int GetAccumulatorCenter() const;
 
+  /**
+   * Change the accumulator center.
+   *
+   * @param accumulatorCenter the new center
+   */
   void SetAccumulatorCenter(int accumulatorCenter);
 
-  std::unique_ptr<CallbackStore> RegisterAccumulatorDeadbandCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterAccumulatorDeadbandCallback(NotifyCallback callback,
+                                      bool initialNotify);
 
+  /**
+   * Get the accumulator deadband.
+   *
+   * @return the accumulator deadband
+   */
   int GetAccumulatorDeadband() const;
 
+  /**
+   * Change the accumulator deadband.
+   *
+   * @param accumulatorDeadband the new deadband
+   */
   void SetAccumulatorDeadband(int accumulatorDeadband);
 
+  /**
+   * Reset all simulation data for this object.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/AnalogOutputSim.h b/wpilibc/src/main/native/include/frc/simulation/AnalogOutputSim.h
index e468fa5..ffec03a 100644
--- a/wpilibc/src/main/native/include/frc/simulation/AnalogOutputSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/AnalogOutputSim.h
@@ -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.
 
 #pragma once
 
@@ -36,20 +33,57 @@
    */
   explicit AnalogOutputSim(int channel);
 
-  std::unique_ptr<CallbackStore> RegisterVoltageCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterVoltageCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the analog output voltage.
+   *
+   * @return the voltage on this analog output
+   */
   double GetVoltage() const;
 
+  /**
+   * Set the analog output voltage.
+   *
+   * @param voltage the new voltage on this analog output
+   */
   void SetVoltage(double voltage);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether this analog output has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Define whether this analog output has been initialized.
+   *
+   * @param initialized whether this object is initialized
+   */
   void SetInitialized(bool initialized);
 
+  /**
+   * Reset all simulation data on this object.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/AnalogTriggerSim.h b/wpilibc/src/main/native/include/frc/simulation/AnalogTriggerSim.h
index 60d62e1..04e9e9b 100644
--- a/wpilibc/src/main/native/include/frc/simulation/AnalogTriggerSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/AnalogTriggerSim.h
@@ -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.
 
 #pragma once
 
@@ -48,27 +45,86 @@
    */
   static AnalogTriggerSim CreateForIndex(int index);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if this analog trigger has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Change whether this analog trigger has been initialized.
+   *
+   * @param initialized the new value
+   */
   void SetInitialized(bool initialized);
 
-  std::unique_ptr<CallbackStore> RegisterTriggerLowerBoundCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterTriggerLowerBoundCallback(NotifyCallback callback,
+                                    bool initialNotify);
 
+  /**
+   * Get the lower bound.
+   *
+   * @return the lower bound
+   */
   double GetTriggerLowerBound() const;
 
+  /**
+   * Change the lower bound.
+   *
+   * @param triggerLowerBound the new lower bound
+   */
   void SetTriggerLowerBound(double triggerLowerBound);
 
-  std::unique_ptr<CallbackStore> RegisterTriggerUpperBoundCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterTriggerUpperBoundCallback(NotifyCallback callback,
+                                    bool initialNotify);
 
+  /**
+   * Get the upper bound.
+   *
+   * @return the upper bound
+   */
   double GetTriggerUpperBound() const;
 
+  /**
+   * Change the upper bound.
+   *
+   * @param triggerUpperBound the new upper bound
+   */
   void SetTriggerUpperBound(double triggerUpperBound);
 
+  /**
+   * Reset all simulation data for this object.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/BatterySim.h b/wpilibc/src/main/native/include/frc/simulation/BatterySim.h
index ef8fb5d..4a350cf 100644
--- a/wpilibc/src/main/native/include/frc/simulation/BatterySim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/BatterySim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -15,13 +12,16 @@
 
 namespace frc::sim {
 
+/**
+ * A utility class to simulate the robot battery.
+ */
 class BatterySim {
  public:
   /**
    * 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.
+   * RoboRioSim::SetVInVoltage(double) to set the simulated battery voltage,
+   * which can then be retrieved with the RobotController::GetBatteryVoltage()
+   * method.
    *
    * @param nominalVoltage The nominal battery voltage. Usually 12v.
    * @param resistance     The forward resistance of the battery. Most batteries
@@ -38,10 +38,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)
+   * RoboRioSimSetVInVoltage(double) to set the simulated battery voltage, which
+   * can then be retrieved with the 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/wpilibc/src/main/native/include/frc/simulation/BuiltInAccelerometerSim.h b/wpilibc/src/main/native/include/frc/simulation/BuiltInAccelerometerSim.h
index 49a581c..9ffcf5b 100644
--- a/wpilibc/src/main/native/include/frc/simulation/BuiltInAccelerometerSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/BuiltInAccelerometerSim.h
@@ -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.
 
 #pragma once
 
@@ -36,41 +33,129 @@
    */
   explicit BuiltInAccelerometerSim(const BuiltInAccelerometer& accel);
 
-  std::unique_ptr<CallbackStore> RegisterActiveCallback(NotifyCallback callback,
-                                                        bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterActiveCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether the accelerometer is active.
+   *
+   * @return true if active
+   */
   bool GetActive() const;
 
+  /**
+   * Define whether this accelerometer is active.
+   *
+   * @param active the new state
+   */
   void SetActive(bool active);
 
-  std::unique_ptr<CallbackStore> RegisterRangeCallback(NotifyCallback callback,
-                                                       bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterRangeCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check the range of this accelerometer.
+   *
+   * @return the accelerometer range
+   */
   HAL_AccelerometerRange GetRange() const;
 
+  /**
+   * Change the range of this accelerometer.
+   *
+   * @param range the new accelerometer range
+   */
   void SetRange(HAL_AccelerometerRange range);
 
-  std::unique_ptr<CallbackStore> RegisterXCallback(NotifyCallback callback,
-                                                   bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterXCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the X axis value.
+   *
+   * @return the X axis measurement
+   */
   double GetX() const;
 
+  /**
+   * Change the X axis value of the accelerometer.
+   *
+   * @param x the new reading of the X axis
+   */
   void SetX(double x);
 
-  std::unique_ptr<CallbackStore> RegisterYCallback(NotifyCallback callback,
-                                                   bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterYCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the Y axis value.
+   *
+   * @return the Y axis measurement
+   */
   double GetY() const;
 
+  /**
+   * Change the Y axis value of the accelerometer.
+   *
+   * @param y the new reading of the Y axis
+   */
   void SetY(double y);
 
-  std::unique_ptr<CallbackStore> RegisterZCallback(NotifyCallback callback,
-                                                   bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterZCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the Z axis value.
+   *
+   * @return the Z axis measurement
+   */
   double GetZ() const;
 
+  /**
+   * Change the Z axis value of the accelerometer.
+   *
+   * @param z the new reading of the Z axis
+   */
   void SetZ(double z);
 
+  /**
+   * Reset all simulation data of this object.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/CTREPCMSim.h b/wpilibc/src/main/native/include/frc/simulation/CTREPCMSim.h
new file mode 100644
index 0000000..0929308
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/simulation/CTREPCMSim.h
@@ -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.
+
+#pragma once
+
+#include <memory>
+
+#include "frc/PneumaticsBase.h"
+#include "frc/simulation/CallbackStore.h"
+
+namespace frc {
+
+class Compressor;
+
+namespace sim {
+
+/**
+ * Class to control a simulated Pneumatic Control Module (PCM).
+ */
+class CTREPCMSim {
+ public:
+  /**
+   * Constructs with the default PCM module number (CAN ID).
+   */
+  CTREPCMSim();
+
+  /**
+   * Constructs from a PCM module number (CAN ID).
+   *
+   * @param module module number
+   */
+  explicit CTREPCMSim(int module);
+
+  explicit CTREPCMSim(const PneumaticsBase& pneumatics);
+
+  /**
+   * Register a callback to be run when a solenoid is initialized on a channel.
+   *
+   * @param callback the callback
+   * @param initialNotify should the callback be run with the initial state
+   * @return the CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check if a solenoid has been initialized on a specific channel.
+   *
+   * @return true if initialized
+   */
+  bool GetInitialized() const;
+
+  /**
+   * Define whether a solenoid has been initialized on a specific channel.
+   *
+   * @param solenoidInitialized is there a solenoid initialized on that channel
+   */
+  void SetInitialized(bool solenoidInitialized);
+
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterSolenoidOutputCallback(
+      int channel, NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check the solenoid output on a specific channel.
+   *
+   * @param channel the channel to check
+   * @return the solenoid output
+   */
+  bool GetSolenoidOutput(int channel) const;
+
+  /**
+   * Change the solenoid output on a specific channel.
+   *
+   * @param channel the channel to check
+   * @param solenoidOutput the new solenoid output
+   */
+  void SetSolenoidOutput(int channel, bool solenoidOutput);
+
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterCompressorOnCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check if the compressor is on.
+   *
+   * @return true if the compressor is active
+   */
+  bool GetCompressorOn() const;
+
+  /**
+   * Set whether the compressor is active.
+   *
+   * @param compressorOn the new value
+   */
+  void SetCompressorOn(bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterClosedLoopEnabledCallback(NotifyCallback callback,
+                                    bool initialNotify);
+
+  /**
+   * Check whether the closed loop compressor control is active.
+   *
+   * @return true if active
+   */
+  bool GetClosedLoopEnabled() const;
+
+  /**
+   * Turn on/off the closed loop control of the compressor.
+   *
+   * @param closedLoopEnabled whether the control loop is active
+   */
+  void SetClosedLoopEnabled(bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterPressureSwitchCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check the value of the pressure switch.
+   *
+   * @return the pressure switch value
+   */
+  bool GetPressureSwitch() const;
+
+  /**
+   * Set the value of the pressure switch.
+   *
+   * @param pressureSwitch the new value
+   */
+  void SetPressureSwitch(bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterCompressorCurrentCallback(NotifyCallback callback,
+                                    bool initialNotify);
+
+  /**
+   * Read the compressor current.
+   *
+   * @return the current of the compressor connected to this module
+   */
+  double GetCompressorCurrent() const;
+
+  /**
+   * Set the compressor current.
+   *
+   * @param compressorCurrent the new compressor current
+   */
+  void SetCompressorCurrent(double compressorCurrent);
+
+  /**
+   * Get the current value of all solenoid outputs.
+   *
+   * @return the solenoid outputs (1 bit per output)
+   */
+  uint8_t GetAllSolenoidOutputs() const;
+
+  /**
+   * Change all of the solenoid outputs.
+   *
+   * @param outputs the new solenoid outputs (1 bit per output)
+   */
+  void SetAllSolenoidOutputs(uint8_t outputs);
+
+  /**
+   * Reset all simulation data for this object.
+   */
+  void ResetData();
+
+ private:
+  int m_index;
+};
+}  // namespace sim
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/CallbackStore.h b/wpilibc/src/main/native/include/frc/simulation/CallbackStore.h
index 379296a..61cc6b2 100644
--- a/wpilibc/src/main/native/include/frc/simulation/CallbackStore.h
+++ b/wpilibc/src/main/native/include/frc/simulation/CallbackStore.h
@@ -1,33 +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.
 
 #pragma once
 
 #include <functional>
+#include <string_view>
 
 #include <hal/Value.h>
-#include <wpi/StringRef.h>
 
-namespace frc {
-namespace sim {
+namespace frc::sim {
 
-using NotifyCallback = std::function<void(wpi::StringRef, const HAL_Value*)>;
+using NotifyCallback = std::function<void(std::string_view, const HAL_Value*)>;
 using ConstBufferCallback = std::function<void(
-    wpi::StringRef, const unsigned char* buffer, unsigned int count)>;
-typedef void (*CancelCallbackFunc)(int32_t index, int32_t uid);
-typedef void (*CancelCallbackNoIndexFunc)(int32_t uid);
-typedef void (*CancelCallbackChannelFunc)(int32_t index, int32_t channel,
-                                          int32_t uid);
+    std::string_view, const unsigned char* buffer, unsigned int count)>;
+using CancelCallbackFunc = void (*)(int32_t index, int32_t uid);
+using CancelCallbackNoIndexFunc = void (*)(int32_t uid);
+using CancelCallbackChannelFunc = void (*)(int32_t index, int32_t channel,
+                                           int32_t uid);
 
 void CallbackStoreThunk(const char* name, void* param, const HAL_Value* value);
 void ConstBufferCallbackStoreThunk(const char* name, void* param,
                                    const unsigned char* buffer,
                                    unsigned int count);
 
+/**
+ * Manages simulation callbacks; each object is associated with a callback.
+ */
 class CallbackStore {
  public:
   CallbackStore(int32_t i, NotifyCallback cb, CancelCallbackNoIndexFunc ccf);
@@ -76,5 +75,4 @@
   enum CancelType { Normal, Channel, NoIndex };
   CancelType cancelType;
 };
-}  // namespace sim
-}  // namespace frc
+}  // namespace frc::sim
diff --git a/wpilibc/src/main/native/include/frc/simulation/DIOSim.h b/wpilibc/src/main/native/include/frc/simulation/DIOSim.h
index f6edb39..9bbd3fb 100644
--- a/wpilibc/src/main/native/include/frc/simulation/DIOSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/DIOSim.h
@@ -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.
 
 #pragma once
 
@@ -44,41 +41,132 @@
    */
   explicit DIOSim(int channel);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether this DIO has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Define whether this DIO has been initialized.
+   *
+   * @param initialized whether this object is initialized
+   */
   void SetInitialized(bool initialized);
 
-  std::unique_ptr<CallbackStore> RegisterValueCallback(NotifyCallback callback,
-                                                       bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterValueCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the value of the DIO port.
+   *
+   * @return the DIO value
+   */
   bool GetValue() const;
 
+  /**
+   * Change the DIO value.
+   *
+   * @param value the new value
+   */
   void SetValue(bool value);
 
-  std::unique_ptr<CallbackStore> RegisterPulseLengthCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterPulseLengthCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the pulse length.
+   *
+   * @return the pulse length of this DIO port
+   */
   double GetPulseLength() const;
 
+  /**
+   * Change the pulse length of this DIO port.
+   *
+   * @param pulseLength the new pulse length
+   */
   void SetPulseLength(double pulseLength);
 
-  std::unique_ptr<CallbackStore> RegisterIsInputCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterIsInputCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether this DIO port is currently an Input.
+   *
+   * @return true if Input
+   */
   bool GetIsInput() const;
 
+  /**
+   * Define whether this DIO port is an Input.
+   *
+   * @param isInput whether this DIO should be an Input
+   */
   void SetIsInput(bool isInput);
 
-  std::unique_ptr<CallbackStore> RegisterFilterIndexCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterFilterIndexCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the filter index.
+   *
+   * @return the filter index of this DIO port
+   */
   int GetFilterIndex() const;
 
+  /**
+   * Change the filter index of this DIO port.
+   *
+   * @param filterIndex the new filter index
+   */
   void SetFilterIndex(int filterIndex);
 
+  /**
+   * Reset all simulation data of this object.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/DifferentialDrivetrainSim.h b/wpilibc/src/main/native/include/frc/simulation/DifferentialDrivetrainSim.h
index a75edb9..e64a652 100644
--- a/wpilibc/src/main/native/include/frc/simulation/DifferentialDrivetrainSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/DifferentialDrivetrainSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -24,42 +21,66 @@
   /**
    * Create a SimDrivetrain.
    *
-   * @param drivetrainPlant   The LinearSystem representing the robot's
-   * drivetrain. This system can be created with
-   * LinearSystemId#createDrivetrainVelocitySystem or
-   * LinearSystemId#identifyDrivetrainSystem.
-   * @param trackWidth        The robot's track width.
-   * @param driveMotor        A {@link DCMotor} representing the left side of
-   * the drivetrain.
-   * @param gearingRatio      The gearingRatio ratio of the left side, as output
-   * over input. This must be the same ratio as the ratio used to identify or
-   * create the drivetrainPlant.
-   * @param wheelRadiusMeters The radius of the wheels on the drivetrain, in
-   * meters.
+   * @param plant The LinearSystem representing the robot's drivetrain. This
+   *              system can be created with
+   *              LinearSystemId::DrivetrainVelocitySystem() or
+   *              LinearSystemId::IdentifyDrivetrainSystem().
+   * @param trackWidth   The robot's track width.
+   * @param driveMotor   A DCMotor representing the left side of the drivetrain.
+   * @param gearingRatio The gearingRatio ratio of the left side, as output over
+   *                     input. This must be the same ratio as the ratio used to
+   *                     identify or create the plant.
+   * @param wheelRadius  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 omitted
+   *                           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.
    */
-  DifferentialDrivetrainSim(const LinearSystem<2, 2, 2>& plant,
-                            units::meter_t trackWidth, DCMotor driveMotor,
-                            double gearingRatio, units::meter_t wheelRadius);
+  DifferentialDrivetrainSim(
+      LinearSystem<2, 2, 2> plant, units::meter_t trackWidth,
+      DCMotor driveMotor, double gearingRatio, units::meter_t wheelRadius,
+      const std::array<double, 7>& measurementStdDevs = {});
 
   /**
    * Create a SimDrivetrain.
    *
-   * @param driveMotor  A {@link DCMotor} representing the left side of the
-   * drivetrain.
+   * @param driveMotor  A 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.
+   *                    output over input. This must be the same ratio as the
+   *                    ratio used to identify or create the plant.
    * @param J           The moment of inertia of the drivetrain about its
-   * center.
+   *                    center.
    * @param mass        The mass of the drivebase.
    * @param wheelRadius The radius of the wheels on the drivetrain.
    * @param trackWidth  The robot's track width, or distance between left and
-   * right wheels.
+   *                    right wheels.
+   * @param measurementStdDevs Standard deviations for measurements, in the form
+   *                           [x, y, heading, left velocity, right velocity,
+   *                           left distance, right distance]áµ€. Can be omitted
+   *                           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.
    */
-  DifferentialDrivetrainSim(frc::DCMotor driveMotor, double gearing,
-                            units::kilogram_square_meter_t J,
-                            units::kilogram_t mass, units::meter_t wheelRadius,
-                            units::meter_t trackWidth);
+  DifferentialDrivetrainSim(
+      frc::DCMotor driveMotor, double gearing, units::kilogram_square_meter_t J,
+      units::kilogram_t mass, units::meter_t wheelRadius,
+      units::meter_t trackWidth,
+      const std::array<double, 7>& measurementStdDevs = {});
+
+  /**
+   * 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.
+   */
+  Eigen::Vector<double, 2> ClampInput(const Eigen::Vector<double, 2>& u);
 
   /**
    * Sets the applied voltage to the drivetrain. Note that positive voltage must
@@ -81,30 +102,18 @@
   /**
    * Updates the simulation.
    *
-   * @param dt The time that's passed since the last {@link #update(double)}
-   * call.
+   * @param dt The time that's passed since the last Update(units::second_t)
+   *           call.
    */
   void Update(units::second_t dt);
 
   /**
-   * Returns an element of the state vector.
-   *
-   * @param state The row of the state vector.
-   */
-  double GetState(int state) const;
-
-  /**
    * Returns the current gearing reduction of the drivetrain, as output over
    * input.
    */
   double GetGearing() const;
 
   /**
-   * Returns the current state vector x.
-   */
-  Eigen::Matrix<double, 7, 1> GetState() const;
-
-  /**
    * Returns the direction the robot is pointing.
    *
    * Note that this angle is counterclockwise-positive, while most gyros are
@@ -118,6 +127,48 @@
   Pose2d GetPose() const;
 
   /**
+   * Get the right encoder position in meters.
+   * @return The encoder position.
+   */
+  units::meter_t GetRightPosition() const {
+    return units::meter_t{GetOutput(State::kRightPosition)};
+  }
+
+  /**
+   * Get the right encoder velocity in meters per second.
+   * @return The encoder velocity.
+   */
+  units::meters_per_second_t GetRightVelocity() const {
+    return units::meters_per_second_t{GetOutput(State::kRightVelocity)};
+  }
+
+  /**
+   * Get the left encoder position in meters.
+   * @return The encoder position.
+   */
+  units::meter_t GetLeftPosition() const {
+    return units::meter_t{GetOutput(State::kLeftPosition)};
+  }
+
+  /**
+   * Get the left encoder velocity in meters per second.
+   * @return The encoder velocity.
+   */
+  units::meters_per_second_t GetLeftVelocity() const {
+    return units::meters_per_second_t{GetOutput(State::kLeftVelocity)};
+  }
+
+  /**
+   * Returns the currently drawn current for the right side.
+   */
+  units::ampere_t GetRightCurrentDraw() const;
+
+  /**
+   * Returns the currently drawn current for the left side.
+   */
+  units::ampere_t GetLeftCurrentDraw() const;
+
+  /**
    * Returns the currently drawn current.
    */
   units::ampere_t GetCurrentDraw() const;
@@ -127,7 +178,7 @@
    *
    * @param state The state.
    */
-  void SetState(const Eigen::Matrix<double, 7, 1>& state);
+  void SetState(const Eigen::Vector<double, 7>& state);
 
   /**
    * Sets the system pose.
@@ -136,8 +187,8 @@
    */
   void SetPose(const frc::Pose2d& pose);
 
-  Eigen::Matrix<double, 7, 1> Dynamics(const Eigen::Matrix<double, 7, 1>& x,
-                                       const Eigen::Matrix<double, 2, 1>& u);
+  Eigen::Vector<double, 7> Dynamics(const Eigen::Vector<double, 7>& x,
+                                    const Eigen::Vector<double, 2>& u);
 
   class State {
    public:
@@ -189,10 +240,16 @@
    * @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 omitted 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.
    */
-  static DifferentialDrivetrainSim CreateKitbotSim(frc::DCMotor motor,
-                                                   double gearing,
-                                                   units::meter_t wheelSize) {
+  static DifferentialDrivetrainSim CreateKitbotSim(
+      frc::DCMotor motor, double gearing, units::meter_t wheelSize,
+      const std::array<double, 7>& measurementStdDevs = {}) {
     // MOI estimation -- note that I = m r^2 for point masses
     units::kilogram_square_meter_t batteryMoi = 12.5_lb * 10_in * 10_in;
     units::kilogram_square_meter_t gearboxMoi = (2.8_lb + 2.0_lb) *
@@ -200,7 +257,8 @@
                                                 * (26_in / 2) * (26_in / 2);
 
     return DifferentialDrivetrainSim{
-        motor, gearing, batteryMoi + gearboxMoi, 25_kg, wheelSize / 2.0, 26_in};
+        motor,           gearing, batteryMoi + gearboxMoi, 60_lb,
+        wheelSize / 2.0, 26_in,   measurementStdDevs};
   }
 
   /**
@@ -210,16 +268,48 @@
    * @param gearing   The gearing reduction used.
    * @param wheelSize The wheel size.
    * @param J         The moment of inertia of the drivebase. This can be
-   * calculated using frc-characterization.
+   * calculated using SysId.
+   * @param measurementStdDevs Standard deviations for measurements, in the form
+   * [x, y, heading, left velocity, right velocity, left distance, right
+   * distance]áµ€. Can be omitted 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.
    */
   static DifferentialDrivetrainSim CreateKitbotSim(
       frc::DCMotor motor, double gearing, units::meter_t wheelSize,
-      units::kilogram_square_meter_t J) {
-    return DifferentialDrivetrainSim{motor, gearing,         J,
-                                     25_kg, wheelSize / 2.0, 26_in};
+      units::kilogram_square_meter_t J,
+      const std::array<double, 7>& measurementStdDevs = {}) {
+    return DifferentialDrivetrainSim{
+        motor, gearing, J, 60_lb, wheelSize / 2.0, 26_in, measurementStdDevs};
   }
 
  private:
+  /**
+   * Returns an element of the state vector.
+   *
+   * @param output The row of the output vector.
+   */
+  double GetOutput(int output) const;
+
+  /**
+   * Returns the current output vector y.
+   */
+  Eigen::Vector<double, 7> GetOutput() const;
+
+  /**
+   * Returns an element of the state vector. Note that this will not include
+   * noise!
+   *
+   * @param output The row of the output vector.
+   */
+  double GetState(int state) const;
+
+  /**
+   * Returns the current state vector x. Note that this will not include noise!
+   */
+  Eigen::Vector<double, 7> GetState() const;
+
   LinearSystem<2, 2, 2> m_plant;
   units::meter_t m_rb;
   units::meter_t m_wheelRadius;
@@ -229,7 +319,9 @@
   double m_originalGearing;
   double m_currentGearing;
 
-  Eigen::Matrix<double, 7, 1> m_x;
-  Eigen::Matrix<double, 2, 1> m_u;
+  Eigen::Vector<double, 7> m_x;
+  Eigen::Vector<double, 2> m_u;
+  Eigen::Vector<double, 7> m_y;
+  std::array<double, 7> m_measurementStdDevs;
 };
 }  // namespace frc::sim
diff --git a/wpilibc/src/main/native/include/frc/simulation/DigitalPWMSim.h b/wpilibc/src/main/native/include/frc/simulation/DigitalPWMSim.h
index 2ff8a12..53caee7 100644
--- a/wpilibc/src/main/native/include/frc/simulation/DigitalPWMSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/DigitalPWMSim.h
@@ -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.
 
 #pragma once
 
@@ -50,27 +47,81 @@
    */
   static DigitalPWMSim CreateForIndex(int index);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether this PWM output has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Define whether this PWM output has been initialized.
+   *
+   * @param initialized whether this object is initialized
+   */
   void SetInitialized(bool initialized);
 
-  std::unique_ptr<CallbackStore> RegisterDutyCycleCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterDutyCycleCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the duty cycle value.
+   *
+   * @return the duty cycle value of this PWM output
+   */
   double GetDutyCycle() const;
 
+  /**
+   * Set the duty cycle value of this PWM output.
+   *
+   * @param dutyCycle the new value
+   */
   void SetDutyCycle(double dutyCycle);
 
-  std::unique_ptr<CallbackStore> RegisterPinCallback(NotifyCallback callback,
-                                                     bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterPinCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check the pin number.
+   *
+   * @return the pin number
+   */
   int GetPin() const;
 
+  /**
+   * Change the pin number.
+   *
+   * @param pin the new pin number
+   */
   void SetPin(int pin);
 
+  /**
+   * Reset all simulation data.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/DriverStationSim.h b/wpilibc/src/main/native/include/frc/simulation/DriverStationSim.h
index 80cf942..412a921 100644
--- a/wpilibc/src/main/native/include/frc/simulation/DriverStationSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/DriverStationSim.h
@@ -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.
 
 #pragma once
 
@@ -14,68 +11,212 @@
 #include "frc/DriverStation.h"
 #include "frc/simulation/CallbackStore.h"
 
-namespace frc {
-namespace sim {
+namespace frc::sim {
 
 /**
  * Class to control a simulated driver station.
  */
 class DriverStationSim {
  public:
-  static std::unique_ptr<CallbackStore> RegisterEnabledCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore> RegisterEnabledCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if the DS is enabled.
+   *
+   * @return true if enabled
+   */
   static bool GetEnabled();
 
+  /**
+   * Change whether the DS is enabled.
+   *
+   * @param enabled the new value
+   */
   static void SetEnabled(bool enabled);
 
-  static std::unique_ptr<CallbackStore> RegisterAutonomousCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterAutonomousCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if the DS is in autonomous.
+   *
+   * @return true if autonomous
+   */
   static bool GetAutonomous();
 
+  /**
+   * Change whether the DS is in autonomous.
+   *
+   * @param autonomous the new value
+   */
   static void SetAutonomous(bool autonomous);
 
-  static std::unique_ptr<CallbackStore> RegisterTestCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore> RegisterTestCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if the DS is in test.
+   *
+   * @return true if test
+   */
   static bool GetTest();
 
+  /**
+   * Change whether the DS is in test.
+   *
+   * @param test the new value
+   */
   static void SetTest(bool test);
 
-  static std::unique_ptr<CallbackStore> RegisterEStopCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore> RegisterEStopCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if eStop has been activated.
+   *
+   * @return true if eStopped
+   */
   static bool GetEStop();
 
+  /**
+   * Set whether eStop is active.
+   *
+   * @param eStop true to activate
+   */
   static void SetEStop(bool eStop);
 
-  static std::unique_ptr<CallbackStore> RegisterFmsAttachedCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterFmsAttachedCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if the FMS is connected.
+   *
+   * @return true if FMS is connected
+   */
   static bool GetFmsAttached();
 
+  /**
+   * Change whether the FMS is connected.
+   *
+   * @param fmsAttached the new value
+   */
   static void SetFmsAttached(bool fmsAttached);
 
-  static std::unique_ptr<CallbackStore> RegisterDsAttachedCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterDsAttachedCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if the DS is attached.
+   *
+   * @return true if attached
+   */
   static bool GetDsAttached();
 
+  /**
+   * Change whether the DS is attached.
+   *
+   * @param dsAttached the new value
+   */
   static void SetDsAttached(bool dsAttached);
 
-  static std::unique_ptr<CallbackStore> RegisterAllianceStationIdCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterAllianceStationIdCallback(NotifyCallback callback,
+                                    bool initialNotify);
 
+  /**
+   * Get the alliance station ID (color + number).
+   *
+   * @return the alliance station color and number
+   */
   static HAL_AllianceStationID GetAllianceStationId();
 
+  /**
+   * Change the alliance station.
+   *
+   * @param allianceStationId the new alliance station
+   */
   static void SetAllianceStationId(HAL_AllianceStationID allianceStationId);
 
-  static std::unique_ptr<CallbackStore> RegisterMatchTimeCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore> RegisterMatchTimeCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the current value of the match timer.
+   *
+   * @return the current match time
+   */
   static double GetMatchTime();
 
+  /**
+   * Sets the match timer.
+   *
+   * @param matchTime the new match time
+   */
   static void SetMatchTime(double matchTime);
 
   /**
@@ -116,7 +257,7 @@
   static int GetJoystickRumble(int stick, int rumbleNum);
 
   /**
-   * Sets the state of one joystick button. Button indexes begin at 1.
+   * Sets the state of one joystick button. %Button indexes begin at 1.
    *
    * @param stick The joystick number
    * @param button The button index, beginning at 1
@@ -242,7 +383,9 @@
    */
   static void SetReplayNumber(int replayNumber);
 
+  /**
+   * Reset all simulation data for the Driver Station.
+   */
   static void ResetData();
 };
-}  // namespace sim
-}  // namespace frc
+}  // namespace frc::sim
diff --git a/wpilibc/src/main/native/include/frc/simulation/DutyCycleEncoderSim.h b/wpilibc/src/main/native/include/frc/simulation/DutyCycleEncoderSim.h
index 5d9a039..19577bb 100644
--- a/wpilibc/src/main/native/include/frc/simulation/DutyCycleEncoderSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/DutyCycleEncoderSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -24,7 +21,7 @@
   /**
    * Constructs from a DutyCycleEncoder object.
    *
-   * @param dutyCycleEncoder DutyCycleEncoder to simulate
+   * @param encoder DutyCycleEncoder to simulate
    */
   explicit DutyCycleEncoderSim(const DutyCycleEncoder& encoder);
 
diff --git a/wpilibc/src/main/native/include/frc/simulation/DutyCycleSim.h b/wpilibc/src/main/native/include/frc/simulation/DutyCycleSim.h
index 40dad13..ec7b48c 100644
--- a/wpilibc/src/main/native/include/frc/simulation/DutyCycleSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/DutyCycleSim.h
@@ -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.
 
 #pragma once
 
@@ -47,27 +44,81 @@
    */
   static DutyCycleSim CreateForIndex(int index);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether this duty cycle input has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Define whether this duty cycle input has been initialized.
+   *
+   * @param initialized whether this object is initialized
+   */
   void SetInitialized(bool initialized);
 
-  std::unique_ptr<CallbackStore> RegisterFrequencyCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterFrequencyCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the frequency.
+   *
+   * @return the duty cycle frequency
+   */
   int GetFrequency() const;
 
-  void SetFrequency(int count);
+  /**
+   * Change the duty cycle frequency.
+   *
+   * @param frequency the new frequency
+   */
+  void SetFrequency(int frequency);
 
-  std::unique_ptr<CallbackStore> RegisterOutputCallback(NotifyCallback callback,
-                                                        bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterOutputCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the output from this duty cycle port.
+   *
+   * @return the output value
+   */
   double GetOutput() const;
 
-  void SetOutput(double period);
+  /**
+   * Change the duty cycle output.
+   *
+   * @param output the new output value
+   */
+  void SetOutput(double output);
 
+  /**
+   * Reset all simulation data for the duty cycle output.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/ElevatorSim.h b/wpilibc/src/main/native/include/frc/simulation/ElevatorSim.h
index 9b7069f..14b6d2d 100644
--- a/wpilibc/src/main/native/include/frc/simulation/ElevatorSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/ElevatorSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -61,20 +58,34 @@
               const std::array<double, 1>& measurementStdDevs = {0.0});
 
   /**
+   * Returns whether the elevator would hit the lower limit.
+   *
+   * @param elevatorHeight The elevator height.
+   * @return Whether the elevator would hit the lower limit.
+   */
+  bool WouldHitLowerLimit(units::meter_t elevatorHeight) const;
+
+  /**
+   * Returns whether the elevator would hit the upper limit.
+   *
+   * @param elevatorHeight The elevator height.
+   * @return Whether the elevator would hit the upper limit.
+   */
+  bool WouldHitUpperLimit(units::meter_t elevatorHeight) const;
+
+  /**
    * Returns whether the elevator has hit the lower limit.
    *
-   * @param x The current elevator state.
    * @return Whether the elevator has hit the lower limit.
    */
-  bool HasHitLowerLimit(const Eigen::Matrix<double, 2, 1>& x) const;
+  bool HasHitLowerLimit() const;
 
   /**
    * Returns whether the elevator has hit the upper limit.
    *
-   * @param x The current elevator state.
    * @return Whether the elevator has hit the upper limit.
    */
-  bool HasHitUpperLimit(const Eigen::Matrix<double, 2, 1>& x) const;
+  bool HasHitUpperLimit() const;
 
   /**
    * Returns the position of the elevator.
@@ -112,9 +123,9 @@
    * @param u           The system inputs (voltage).
    * @param dt          The time difference between controller updates.
    */
-  Eigen::Matrix<double, 2, 1> UpdateX(
-      const Eigen::Matrix<double, 2, 1>& currentXhat,
-      const Eigen::Matrix<double, 1, 1>& u, units::second_t dt) override;
+  Eigen::Vector<double, 2> UpdateX(const Eigen::Vector<double, 2>& currentXhat,
+                                   const Eigen::Vector<double, 1>& u,
+                                   units::second_t dt) override;
 
  private:
   DCMotor m_gearbox;
diff --git a/wpilibc/src/main/native/include/frc/simulation/EncoderSim.h b/wpilibc/src/main/native/include/frc/simulation/EncoderSim.h
index 4049ab8..0d578b4 100644
--- a/wpilibc/src/main/native/include/frc/simulation/EncoderSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/EncoderSim.h
@@ -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.
 
 #pragma once
 
@@ -48,77 +45,261 @@
    */
   static EncoderSim CreateForIndex(int index);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the Initialized value of the encoder.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Change the Initialized value of the encoder.
+   *
+   * @param initialized the new value
+   */
   void SetInitialized(bool initialized);
 
-  std::unique_ptr<CallbackStore> RegisterCountCallback(NotifyCallback callback,
-                                                       bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterCountCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the count of the encoder.
+   *
+   * @return the count
+   */
   int GetCount() const;
 
+  /**
+   * Change the count of the encoder.
+   *
+   * @param count the new count
+   */
   void SetCount(int count);
 
-  std::unique_ptr<CallbackStore> RegisterPeriodCallback(NotifyCallback callback,
-                                                        bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterPeriodCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the period of the encoder.
+   *
+   * @return the encoder period
+   */
   double GetPeriod() const;
 
+  /**
+   * Change the encoder period.
+   *
+   * @param period the new period
+   */
   void SetPeriod(double period);
 
-  std::unique_ptr<CallbackStore> RegisterResetCallback(NotifyCallback callback,
-                                                       bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterResetCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check if the encoder has been reset.
+   *
+   * @return true if reset
+   */
   bool GetReset() const;
 
+  /**
+   * Change the reset property of the encoder.
+   *
+   * @param reset the new value
+   */
   void SetReset(bool reset);
 
-  std::unique_ptr<CallbackStore> RegisterMaxPeriodCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterMaxPeriodCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the max period of the encoder.
+   *
+   * @return the max period of the encoder
+   */
   double GetMaxPeriod() const;
 
+  /**
+   * Change the max period of the encoder.
+   *
+   * @param maxPeriod the new value
+   */
   void SetMaxPeriod(double maxPeriod);
 
-  std::unique_ptr<CallbackStore> RegisterDirectionCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterDirectionCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the direction of the encoder.
+   *
+   * @return the direction of the encoder
+   */
   bool GetDirection() const;
 
+  /**
+   * Set the direction of the encoder.
+   *
+   * @param direction the new direction
+   */
   void SetDirection(bool direction);
 
-  std::unique_ptr<CallbackStore> RegisterReverseDirectionCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterReverseDirectionCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the reverse direction of the encoder.
+   *
+   * @return the reverse direction of the encoder
+   */
   bool GetReverseDirection() const;
 
+  /**
+   * Set the reverse direction.
+   *
+   * @param reverseDirection the new value
+   */
   void SetReverseDirection(bool reverseDirection);
 
-  std::unique_ptr<CallbackStore> RegisterSamplesToAverageCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterSamplesToAverageCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the samples-to-average value.
+   *
+   * @return the samples-to-average value
+   */
   int GetSamplesToAverage() const;
 
+  /**
+   * Set the samples-to-average value.
+   *
+   * @param samplesToAverage the new value
+   */
   void SetSamplesToAverage(int samplesToAverage);
 
-  std::unique_ptr<CallbackStore> RegisterDistancePerPulseCallback(
+  /**
+   * Register a callback on the distance per pulse value of this encoder.
+   *
+   * @param callback the callback that will be called whenever the
+   *                 distance per pulse is changed
+   * @param initialNotify if true, the callback will be run on the initial value
+   * @return the CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterDistancePerPulseCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Read the distance per pulse of the encoder.
+   *
+   * @return the encoder distance per pulse
+   */
   double GetDistancePerPulse() const;
 
+  /**
+   * Change the encoder distance per pulse.
+   *
+   * @param distancePerPulse the new distance per pulse
+   */
   void SetDistancePerPulse(double distancePerPulse);
 
+  /**
+   * Resets all simulation data for this encoder.
+   */
   void ResetData();
 
+  /**
+   * Change the encoder distance.
+   *
+   * @param distance the new distance
+   */
   void SetDistance(double distance);
 
+  /**
+   * Read the distance of the encoder.
+   *
+   * @return the encoder distance
+   */
   double GetDistance();
 
+  /**
+   * Change the rate of the encoder.
+   *
+   * @param rate the new rate
+   */
   void SetRate(double rate);
 
+  /**
+   * Get the rate of the encoder.
+   *
+   * @return the rate of change
+   */
   double GetRate();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/Field2d.h b/wpilibc/src/main/native/include/frc/simulation/Field2d.h
deleted file mode 100644
index de30847..0000000
--- a/wpilibc/src/main/native/include/frc/simulation/Field2d.h
+++ /dev/null
@@ -1,70 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <hal/SimDevice.h>
-#include <units/length.h>
-
-#include "frc/geometry/Pose2d.h"
-#include "frc/geometry/Rotation2d.h"
-
-namespace frc {
-
-/**
- * 2D representation of game field (for simulation).
- *
- * In non-simulation mode this simply stores and returns the robot pose.
- *
- * 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).
- *
- * 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.
- */
-class Field2d {
- public:
-  Field2d();
-
-  /**
-   * Set the robot pose from a Pose object.
-   *
-   * @param pose 2D pose
-   */
-  void SetRobotPose(const Pose2d& pose);
-
-  /**
-   * Set the robot pose from x, y, and rotation.
-   *
-   * @param x X location
-   * @param y Y location
-   * @param rotation rotation
-   */
-  void SetRobotPose(units::meter_t x, units::meter_t y, Rotation2d rotation);
-
-  /**
-   * Get the robot pose.
-   *
-   * @return 2D pose
-   */
-  Pose2d GetRobotPose();
-
- private:
-  Pose2d m_pose;
-
-  hal::SimDevice m_device;
-  hal::SimDouble m_x;
-  hal::SimDouble m_y;
-  hal::SimDouble m_rot;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/FlywheelSim.h b/wpilibc/src/main/native/include/frc/simulation/FlywheelSim.h
index 1c47c45..9f2272c 100644
--- a/wpilibc/src/main/native/include/frc/simulation/FlywheelSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/FlywheelSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -21,7 +18,7 @@
 class FlywheelSim : public LinearSystemSim<1, 1, 1> {
  public:
   /**
-   * Creates a simulated flywhel mechanism.
+   * Creates a simulated flywheel mechanism.
    *
    * @param plant              The linear system representing the flywheel.
    * @param gearbox            The type of and number of motors in the flywheel
@@ -35,7 +32,7 @@
               const std::array<double, 1>& measurementStdDevs = {0.0});
 
   /**
-   * Creates a simulated flywhel mechanism.
+   * Creates a simulated flywheel mechanism.
    *
    * @param gearbox            The type of and number of motors in the flywheel
    *                           gearbox.
diff --git a/wpilibc/src/main/native/include/frc/simulation/GenericHIDSim.h b/wpilibc/src/main/native/include/frc/simulation/GenericHIDSim.h
index 1705200..399e0c1 100644
--- a/wpilibc/src/main/native/include/frc/simulation/GenericHIDSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/GenericHIDSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -41,30 +38,101 @@
    */
   void NotifyNewData();
 
+  /**
+   * Set the value of a given button.
+   *
+   * @param button the button to set
+   * @param value the new value
+   */
   void SetRawButton(int button, bool value);
 
+  /**
+   * Set the value of a given axis.
+   *
+   * @param axis the axis to set
+   * @param value the new value
+   */
   void SetRawAxis(int axis, double value);
 
+  /**
+   * Set the value of a given POV.
+   *
+   * @param pov the POV to set
+   * @param value the new value
+   */
   void SetPOV(int pov, int value);
 
+  /**
+   * Set the value of the default POV (port 0).
+   *
+   * @param value the new value
+   */
   void SetPOV(int value);
 
+  /**
+   * Set the axis count of this device.
+   *
+   * @param count the new axis count
+   */
   void SetAxisCount(int count);
 
+  /**
+   * Set the POV count of this device.
+   *
+   * @param count the new POV count
+   */
   void SetPOVCount(int count);
 
+  /**
+   * Set the button count of this device.
+   *
+   * @param count the new button count
+   */
   void SetButtonCount(int count);
 
+  /**
+   * Set the type of this device.
+   *
+   * @param type the new device type
+   */
   void SetType(GenericHID::HIDType type);
 
+  /**
+   * Set the name of this device.
+   *
+   * @param name the new device name
+   */
   void SetName(const char* name);
 
+  /**
+   * Set the type of an axis.
+   *
+   * @param axis the axis
+   * @param type the type
+   */
   void SetAxisType(int axis, int type);
 
+  /**
+   * Read the output of a button.
+   *
+   * @param outputNumber the button number
+   * @return the value of the button (true = pressed)
+   */
   bool GetOutput(int outputNumber);
 
+  /**
+   * Get the encoded 16-bit integer that passes button values.
+   *
+   * @return the button values
+   */
   int64_t GetOutputs();
 
+  /**
+   * Get the joystick rumble.
+   *
+   * @param type the rumble to read
+   * @return the rumble value
+   */
   double GetRumble(GenericHID::RumbleType type);
 
  protected:
diff --git a/wpilibc/src/main/native/include/frc/simulation/JoystickSim.h b/wpilibc/src/main/native/include/frc/simulation/JoystickSim.h
index 5735728..db573ad 100644
--- a/wpilibc/src/main/native/include/frc/simulation/JoystickSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/JoystickSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -34,18 +31,53 @@
    */
   explicit JoystickSim(int port);
 
+  /**
+   * Set the X value of the joystick.
+   *
+   * @param value the new X value
+   */
   void SetX(double value);
 
+  /**
+   * Set the Y value of the joystick.
+   *
+   * @param value the new Y value
+   */
   void SetY(double value);
 
+  /**
+   * Set the Z value of the joystick.
+   *
+   * @param value the new Z value
+   */
   void SetZ(double value);
 
+  /**
+   * Set the twist value of the joystick.
+   *
+   * @param value the new twist value
+   */
   void SetTwist(double value);
 
+  /**
+   * Set the throttle value of the joystick.
+   *
+   * @param value the new throttle value
+   */
   void SetThrottle(double value);
 
+  /**
+   * Set the trigger value of the joystick.
+   *
+   * @param state the new value
+   */
   void SetTrigger(bool state);
 
+  /**
+   * Set the top state of the joystick.
+   *
+   * @param state the new state
+   */
   void SetTop(bool state);
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/LinearSystemSim.h b/wpilibc/src/main/native/include/frc/simulation/LinearSystemSim.h
index 4f3c658..61cbd46 100644
--- a/wpilibc/src/main/native/include/frc/simulation/LinearSystemSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/LinearSystemSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -13,6 +10,7 @@
 #include <units/current.h>
 #include <units/time.h>
 
+#include "frc/RobotController.h"
 #include "frc/StateSpaceUtil.h"
 #include "frc/system/LinearSystem.h"
 
@@ -38,13 +36,13 @@
    * @param system             The system to simulate.
    * @param measurementStdDevs The standard deviations of the measurements.
    */
-  LinearSystemSim(const LinearSystem<States, Inputs, Outputs>& system,
-                  const std::array<double, Outputs>& measurementStdDevs =
-                      std::array<double, Outputs>{})
+  explicit LinearSystemSim(
+      const LinearSystem<States, Inputs, Outputs>& system,
+      const std::array<double, Outputs>& measurementStdDevs = {})
       : m_plant(system), m_measurementStdDevs(measurementStdDevs) {
-    m_x = Eigen::Matrix<double, States, 1>::Zero();
-    m_y = Eigen::Matrix<double, Outputs, 1>::Zero();
-    m_u = Eigen::Matrix<double, Inputs, 1>::Zero();
+    m_x = Eigen::Vector<double, States>::Zero();
+    m_y = Eigen::Vector<double, Outputs>::Zero();
+    m_u = Eigen::Vector<double, Inputs>::Zero();
   }
 
   /**
@@ -71,7 +69,7 @@
    *
    * @return The current output of the plant.
    */
-  const Eigen::Matrix<double, Outputs, 1>& GetOutput() const { return m_y; }
+  const Eigen::Vector<double, Outputs>& GetOutput() const { return m_y; }
 
   /**
    * Returns an element of the current output of the plant.
@@ -86,7 +84,7 @@
    *
    * @param u The system inputs.
    */
-  void SetInput(const Eigen::Matrix<double, Inputs, 1>& u) { m_u = u; }
+  void SetInput(const Eigen::Vector<double, Inputs>& u) { m_u = ClampInput(u); }
 
   /*
    * Sets the system inputs.
@@ -94,14 +92,17 @@
    * @param row   The row in the input matrix to set.
    * @param value The value to set the row to.
    */
-  void SetInput(int row, double value) { m_u(row, 0) = value; }
+  void SetInput(int row, double value) {
+    m_u(row, 0) = value;
+    ClampInput(m_u);
+  }
 
   /**
    * Sets the system state.
    *
    * @param state The new state.
    */
-  void SetState(const Eigen::Matrix<double, States, 1>& state) { m_x = state; }
+  void SetState(const Eigen::Vector<double, States>& state) { m_x = state; }
 
   /**
    * Returns the current drawn by this simulated system. Override this method to
@@ -121,17 +122,29 @@
    * @param u           The system inputs (usually voltage).
    * @param dt          The time difference between controller updates.
    */
-  virtual Eigen::Matrix<double, States, 1> UpdateX(
-      const Eigen::Matrix<double, States, 1>& currentXhat,
-      const Eigen::Matrix<double, Inputs, 1>& u, units::second_t dt) {
+  virtual Eigen::Vector<double, States> UpdateX(
+      const Eigen::Vector<double, States>& currentXhat,
+      const Eigen::Vector<double, Inputs>& u, units::second_t dt) {
     return m_plant.CalculateX(currentXhat, u, dt);
   }
 
+  /**
+   * 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.
+   */
+  Eigen::Vector<double, Inputs> ClampInput(Eigen::Vector<double, Inputs> u) {
+    return frc::NormalizeInputVector<Inputs>(
+        u, frc::RobotController::GetInputVoltage());
+  }
+
   LinearSystem<States, Inputs, Outputs> m_plant;
 
-  Eigen::Matrix<double, States, 1> m_x;
-  Eigen::Matrix<double, Outputs, 1> m_y;
-  Eigen::Matrix<double, Inputs, 1> m_u;
+  Eigen::Vector<double, States> m_x;
+  Eigen::Vector<double, Outputs> m_y;
+  Eigen::Vector<double, Inputs> m_u;
   std::array<double, Outputs> m_measurementStdDevs;
 };
 }  // namespace frc::sim
diff --git a/wpilibc/src/main/native/include/frc/simulation/Mechanism2D.h b/wpilibc/src/main/native/include/frc/simulation/Mechanism2D.h
deleted file mode 100644
index 3d61cf5..0000000
--- a/wpilibc/src/main/native/include/frc/simulation/Mechanism2D.h
+++ /dev/null
@@ -1,45 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <map>
-#include <string>
-
-#include <hal/SimDevice.h>
-#include <wpi/StringMap.h>
-
-#include "frc/geometry/Pose2d.h"
-#include "frc/geometry/Rotation2d.h"
-
-namespace frc {
-class Mechanism2D {
- public:
-  Mechanism2D();
-
-  /**
-   * Set/Create the angle of a ligament
-   *
-   * @param ligamentPath json path to the ligament
-   * @param angle to set the ligament
-   */
-  void SetLigamentAngle(const wpi::Twine& ligamentPath, float angle);
-
-  /**
-   * Set/Create the length of a ligament
-   *
-   * @param ligamentPath json path to the ligament
-   * @param length to set the ligament
-   */
-  void SetLigamentLength(const wpi::Twine& ligamentPath, float length);
-
- private:
-  wpi::StringMap<hal::SimDouble> createdItems;
-  hal::SimDevice m_device;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/PCMSim.h b/wpilibc/src/main/native/include/frc/simulation/PCMSim.h
deleted file mode 100644
index 2e3ed5e..0000000
--- a/wpilibc/src/main/native/include/frc/simulation/PCMSim.h
+++ /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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-
-#include "frc/simulation/CallbackStore.h"
-
-namespace frc {
-
-class Compressor;
-
-namespace sim {
-
-/**
- * Class to control a simulated Pneumatic Control Module (PCM).
- */
-class PCMSim {
- public:
-  /**
-   * Constructs with the default PCM module number (CAN ID).
-   */
-  PCMSim();
-
-  /**
-   * Constructs from a PCM module number (CAN ID).
-   *
-   * @param module module number
-   */
-  explicit PCMSim(int module);
-
-  /**
-   * Constructs from a Compressor object.
-   *
-   * @param compressor Compressor connected to PCM to simulate
-   */
-  explicit PCMSim(const Compressor& compressor);
-
-  std::unique_ptr<CallbackStore> RegisterSolenoidInitializedCallback(
-      int channel, NotifyCallback callback, bool initialNotify);
-
-  bool GetSolenoidInitialized(int channel) const;
-
-  void SetSolenoidInitialized(int channel, bool solenoidInitialized);
-
-  std::unique_ptr<CallbackStore> RegisterSolenoidOutputCallback(
-      int channel, NotifyCallback callback, bool initialNotify);
-
-  bool GetSolenoidOutput(int channel) const;
-
-  void SetSolenoidOutput(int channel, bool solenoidOutput);
-
-  std::unique_ptr<CallbackStore> RegisterCompressorInitializedCallback(
-      NotifyCallback callback, bool initialNotify);
-
-  bool GetCompressorInitialized() const;
-
-  void SetCompressorInitialized(bool compressorInitialized);
-
-  std::unique_ptr<CallbackStore> RegisterCompressorOnCallback(
-      NotifyCallback callback, bool initialNotify);
-
-  bool GetCompressorOn() const;
-
-  void SetCompressorOn(bool compressorOn);
-
-  std::unique_ptr<CallbackStore> RegisterClosedLoopEnabledCallback(
-      NotifyCallback callback, bool initialNotify);
-
-  bool GetClosedLoopEnabled() const;
-
-  void SetClosedLoopEnabled(bool closedLoopEnabled);
-
-  std::unique_ptr<CallbackStore> RegisterPressureSwitchCallback(
-      NotifyCallback callback, bool initialNotify);
-
-  bool GetPressureSwitch() const;
-
-  void SetPressureSwitch(bool pressureSwitch);
-
-  std::unique_ptr<CallbackStore> RegisterCompressorCurrentCallback(
-      NotifyCallback callback, bool initialNotify);
-
-  double GetCompressorCurrent() const;
-
-  void SetCompressorCurrent(double compressorCurrent);
-
-  uint8_t GetAllSolenoidOutputs() const;
-
-  void SetAllSolenoidOutputs(uint8_t outputs);
-
-  void ResetData();
-
- private:
-  int m_index;
-};
-}  // namespace sim
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/PDPSim.h b/wpilibc/src/main/native/include/frc/simulation/PDPSim.h
deleted file mode 100644
index c67815f..0000000
--- a/wpilibc/src/main/native/include/frc/simulation/PDPSim.h
+++ /dev/null
@@ -1,77 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-
-#include "frc/simulation/CallbackStore.h"
-
-namespace frc {
-
-class PowerDistributionPanel;
-
-namespace sim {
-
-/**
- * Class to control a simulated Power Distribution Panel (PDP).
- */
-class PDPSim {
- public:
-  /**
-   * Constructs from a PDP module number (CAN ID).
-   *
-   * @param module module number
-   */
-  explicit PDPSim(int module = 0);
-
-  /**
-   * Constructs from a PowerDistributionPanel object.
-   *
-   * @param pdp PowerDistributionPanel to simulate
-   */
-  explicit PDPSim(const PowerDistributionPanel& pdp);
-
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
-      NotifyCallback callback, bool initialNotify);
-
-  bool GetInitialized() const;
-
-  void SetInitialized(bool initialized);
-
-  std::unique_ptr<CallbackStore> RegisterTemperatureCallback(
-      NotifyCallback callback, bool initialNotify);
-
-  double GetTemperature() const;
-
-  void SetTemperature(double temperature);
-
-  std::unique_ptr<CallbackStore> RegisterVoltageCallback(
-      NotifyCallback callback, bool initialNotify);
-
-  double GetVoltage() const;
-
-  void SetVoltage(double voltage);
-
-  std::unique_ptr<CallbackStore> RegisterCurrentCallback(
-      int channel, NotifyCallback callback, bool initialNotify);
-
-  double GetCurrent(int channel) const;
-
-  void SetCurrent(int channel, double current);
-
-  void GetAllCurrents(double* currents) const;
-
-  void SetAllCurrents(const double* currents);
-
-  void ResetData();
-
- private:
-  int m_index;
-};
-}  // namespace sim
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/PS4ControllerSim.h b/wpilibc/src/main/native/include/frc/simulation/PS4ControllerSim.h
new file mode 100644
index 0000000..a599ad9
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/simulation/PS4ControllerSim.h
@@ -0,0 +1,176 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include "frc/simulation/GenericHIDSim.h"
+
+namespace frc {
+
+class PS4Controller;
+
+namespace sim {
+
+/**
+ * Class to control a simulated PS4 controller.
+ */
+class PS4ControllerSim : public GenericHIDSim {
+ public:
+  /**
+   * Constructs from a PS4Controller object.
+   *
+   * @param joystick controller to simulate
+   */
+  explicit PS4ControllerSim(const PS4Controller& joystick);
+
+  /**
+   * Constructs from a joystick port number.
+   *
+   * @param port port number
+   */
+  explicit PS4ControllerSim(int port);
+
+  /**
+   * Change the X axis value of the controller's left stick.
+   *
+   * @param value the new value
+   */
+  void SetLeftX(double value);
+
+  /**
+   * Change the X axis value of the controller's right stick.
+   *
+   * @param value the new value
+   */
+  void SetRightX(double value);
+
+  /**
+   * Change the Y axis value of the controller's left stick.
+   *
+   * @param value the new value
+   */
+  void SetLeftY(double value);
+
+  /**
+   * Change the Y axis value of the controller's right stick.
+   *
+   * @param value the new value
+   */
+  void SetRightY(double value);
+
+  /**
+   * Change the L2 axis axis value of the controller.
+   *
+   * @param value the new value
+   */
+  void SetL2Axis(double value);
+
+  /**
+   * Change the R2 axis value of the controller.
+   *
+   * @param value the new value
+   */
+  void SetR2Axis(double value);
+
+  /**
+   * Change the value of the Square button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetSquareButton(bool value);
+
+  /**
+   * Change the value of the Cross button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetCrossButton(bool value);
+
+  /**
+   * Change the value of the Circle button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetCircleButton(bool value);
+
+  /**
+   * Change the value of the Triangle button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetTriangleButton(bool value);
+
+  /**
+   * Change the value of the L1 button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetL1Button(bool value);
+
+  /**
+   * Change the value of the R1 button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetR1Button(bool value);
+
+  /**
+   * Change the value of the L2 button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetL2Button(bool value);
+
+  /**
+   * Change the value of the R2 button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetR2Button(bool value);
+
+  /**
+   * Change the value of the Share button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetShareButton(bool value);
+
+  /**
+   * Change the value of the Options button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetOptionsButton(bool value);
+
+  /**
+   * Change the value of the L3 (left stick) button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetL3Button(bool value);
+
+  /**
+   * Change the value of the R3 (right stick) button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetR3Button(bool value);
+
+  /**
+   * Change the value of the PS button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetPSButton(bool value);
+
+  /**
+   * Change the value of the touchpad button on the controller.
+   *
+   * @param value the new value
+   */
+  void SetTouchpad(bool value);
+};
+
+}  // namespace sim
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/PWMSim.h b/wpilibc/src/main/native/include/frc/simulation/PWMSim.h
index ca2dfca..97e9b1f 100644
--- a/wpilibc/src/main/native/include/frc/simulation/PWMSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/PWMSim.h
@@ -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.
 
 #pragma once
 
@@ -36,48 +33,153 @@
    */
   explicit PWMSim(int channel);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether the PWM has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitialized() const;
 
+  /**
+   * Define whether the PWM has been initialized.
+   *
+   * @param initialized whether this object is initialized
+   */
   void SetInitialized(bool initialized);
 
-  std::unique_ptr<CallbackStore> RegisterRawValueCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterRawValueCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the PWM raw value.
+   *
+   * @return the PWM raw value
+   */
   int GetRawValue() const;
 
+  /**
+   * Set the PWM raw value.
+   *
+   * @param rawValue the PWM raw value
+   */
   void SetRawValue(int rawValue);
 
-  std::unique_ptr<CallbackStore> RegisterSpeedCallback(NotifyCallback callback,
-                                                       bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterSpeedCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the PWM speed.
+   *
+   * @return the PWM speed (-1.0 to 1.0)
+   */
   double GetSpeed() const;
 
+  /**
+   * Set the PWM speed.
+   *
+   * @param speed the PWM speed (-1.0 to 1.0)
+   */
   void SetSpeed(double speed);
 
-  std::unique_ptr<CallbackStore> RegisterPositionCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterPositionCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the PWM position.
+   *
+   * @return the PWM position (0.0 to 1.0)
+   */
   double GetPosition() const;
 
+  /**
+   * Set the PWM position.
+   *
+   * @param position the PWM position (0.0 to 1.0)
+   */
   void SetPosition(double position);
 
-  std::unique_ptr<CallbackStore> RegisterPeriodScaleCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterPeriodScaleCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the PWM period scale.
+   *
+   * @return the PWM period scale
+   */
   int GetPeriodScale() const;
 
+  /**
+   * Set the PWM period scale.
+   *
+   * @param periodScale the PWM period scale
+   */
   void SetPeriodScale(int periodScale);
 
-  std::unique_ptr<CallbackStore> RegisterZeroLatchCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterZeroLatchCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether the PWM is zero latched.
+   *
+   * @return true if zero latched
+   */
   bool GetZeroLatch() const;
 
+  /**
+   * Define whether the PWM has been zero latched.
+   *
+   * @param zeroLatch true to indicate zero latched
+   */
   void SetZeroLatch(bool zeroLatch);
 
+  /**
+   * Reset all simulation data.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/PowerDistributionSim.h b/wpilibc/src/main/native/include/frc/simulation/PowerDistributionSim.h
new file mode 100644
index 0000000..ac54da2
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/simulation/PowerDistributionSim.h
@@ -0,0 +1,167 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <memory>
+
+#include "frc/simulation/CallbackStore.h"
+
+namespace frc {
+
+class PowerDistribution;
+
+namespace sim {
+
+/**
+ * Class to control a simulated Power Distribution Panel (PowerDistribution).
+ */
+class PowerDistributionSim {
+ public:
+  /**
+   * Constructs from a PowerDistribution module number (CAN ID).
+   *
+   * @param module module number
+   */
+  explicit PowerDistributionSim(int module = 0);
+
+  /**
+   * Constructs from a PowerDistribution object.
+   *
+   * @param pdp PowerDistribution to simulate
+   */
+  explicit PowerDistributionSim(const PowerDistribution& pdp);
+
+  /**
+   * Register a callback to be run when the PowerDistribution is initialized.
+   *
+   * @param callback the callback
+   * @param initialNotify whether to run the callback with the initial state
+   * @return the CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check whether the PowerDistribution has been initialized.
+   *
+   * @return true if initialized
+   */
+  bool GetInitialized() const;
+
+  /**
+   * Define whether the PowerDistribution has been initialized.
+   *
+   * @param initialized whether this object is initialized
+   */
+  void SetInitialized(bool initialized);
+
+  /**
+   * Register a callback to be run whenever the PowerDistribution temperature
+   * changes.
+   *
+   * @param callback the callback
+   * @param initialNotify whether to call the callback with the initial state
+   * @return the CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterTemperatureCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check the temperature of the PowerDistribution.
+   *
+   * @return the PowerDistribution temperature
+   */
+  double GetTemperature() const;
+
+  /**
+   * Define the PowerDistribution temperature.
+   *
+   * @param temperature the new PowerDistribution temperature
+   */
+  void SetTemperature(double temperature);
+
+  /**
+   * Register a callback to be run whenever the PowerDistribution voltage
+   * changes.
+   *
+   * @param callback the callback
+   * @param initialNotify whether to call the callback with the initial state
+   * @return the CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterVoltageCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check the PowerDistribution voltage.
+   *
+   * @return the PowerDistribution voltage.
+   */
+  double GetVoltage() const;
+
+  /**
+   * Set the PowerDistribution voltage.
+   *
+   * @param voltage the new PowerDistribution voltage
+   */
+  void SetVoltage(double voltage);
+
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterCurrentCallback(
+      int channel, NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Read the current in one of the PowerDistribution channels.
+   *
+   * @param channel the channel to check
+   * @return the current in the given channel
+   */
+  double GetCurrent(int channel) const;
+
+  /**
+   * Change the current in the given channel.
+   *
+   * @param channel the channel to edit
+   * @param current the new current for the channel
+   */
+  void SetCurrent(int channel, double current);
+
+  /**
+   * Read the current of all of the PowerDistribution channels.
+   *
+   * @param currents output array; set to the current in each channel. The
+   *                 array must be big enough to hold all the PowerDistribution
+   *                 channels
+   * @param length   length of output array
+   */
+  void GetAllCurrents(double* currents, int length) const;
+
+  /**
+   * Change the current in all of the PowerDistribution channels.
+   *
+   * @param currents array containing the current values for each channel. The
+   *                 array must be big enough to hold all the PowerDistribution
+   *                 channels
+   * @param length   length of array
+   */
+  void SetAllCurrents(const double* currents, int length);
+
+  /**
+   * Reset all PowerDistribution simulation data.
+   */
+  void ResetData();
+
+ private:
+  int m_index;
+};
+}  // namespace sim
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/REVPHSim.h b/wpilibc/src/main/native/include/frc/simulation/REVPHSim.h
new file mode 100644
index 0000000..97e31bf
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/simulation/REVPHSim.h
@@ -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.
+
+#pragma once
+
+#include <memory>
+
+#include "frc/PneumaticsBase.h"
+#include "frc/simulation/CallbackStore.h"
+
+namespace frc {
+
+class Compressor;
+
+namespace sim {
+
+/**
+ * Class to control a simulated Pneumatic Control Module (PCM).
+ */
+class REVPHSim {
+ public:
+  /**
+   * Constructs with the default PCM module number (CAN ID).
+   */
+  REVPHSim();
+
+  /**
+   * Constructs from a PCM module number (CAN ID).
+   *
+   * @param module module number
+   */
+  explicit REVPHSim(int module);
+
+  explicit REVPHSim(const PneumaticsBase& pneumatics);
+
+  /**
+   * Register a callback to be run when a solenoid is initialized on a channel.
+   *
+   * @param callback the callback
+   * @param initialNotify should the callback be run with the initial state
+   * @return the CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterInitializedCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check if a solenoid has been initialized on a specific channel.
+   *
+   * @return true if initialized
+   */
+  bool GetInitialized() const;
+
+  /**
+   * Define whether a solenoid has been initialized on a specific channel.
+   *
+   * @param solenoidInitialized is there a solenoid initialized on that channel
+   */
+  void SetInitialized(bool solenoidInitialized);
+
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterSolenoidOutputCallback(
+      int channel, NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check the solenoid output on a specific channel.
+   *
+   * @param channel the channel to check
+   * @return the solenoid output
+   */
+  bool GetSolenoidOutput(int channel) const;
+
+  /**
+   * Change the solenoid output on a specific channel.
+   *
+   * @param channel the channel to check
+   * @param solenoidOutput the new solenoid output
+   */
+  void SetSolenoidOutput(int channel, bool solenoidOutput);
+
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterCompressorOnCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check if the compressor is on.
+   *
+   * @return true if the compressor is active
+   */
+  bool GetCompressorOn() const;
+
+  /**
+   * Set whether the compressor is active.
+   *
+   * @param compressorOn the new value
+   */
+  void SetCompressorOn(bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterClosedLoopEnabledCallback(NotifyCallback callback,
+                                    bool initialNotify);
+
+  /**
+   * Check whether the closed loop compressor control is active.
+   *
+   * @return true if active
+   */
+  bool GetClosedLoopEnabled() const;
+
+  /**
+   * Turn on/off the closed loop control of the compressor.
+   *
+   * @param closedLoopEnabled whether the control loop is active
+   */
+  void SetClosedLoopEnabled(bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterPressureSwitchCallback(
+      NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Check the value of the pressure switch.
+   *
+   * @return the pressure switch value
+   */
+  bool GetPressureSwitch() const;
+
+  /**
+   * Set the value of the pressure switch.
+   *
+   * @param pressureSwitch the new value
+   */
+  void SetPressureSwitch(bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterCompressorCurrentCallback(NotifyCallback callback,
+                                    bool initialNotify);
+
+  /**
+   * Read the compressor current.
+   *
+   * @return the current of the compressor connected to this module
+   */
+  double GetCompressorCurrent() const;
+
+  /**
+   * Set the compressor current.
+   *
+   * @param compressorCurrent the new compressor current
+   */
+  void SetCompressorCurrent(double compressorCurrent);
+
+  /**
+   * Get the current value of all solenoid outputs.
+   *
+   * @return the solenoid outputs (1 bit per output)
+   */
+  uint8_t GetAllSolenoidOutputs() const;
+
+  /**
+   * Change all of the solenoid outputs.
+   *
+   * @param outputs the new solenoid outputs (1 bit per output)
+   */
+  void SetAllSolenoidOutputs(uint8_t outputs);
+
+  /**
+   * Reset all simulation data for this object.
+   */
+  void ResetData();
+
+ private:
+  int m_index;
+};
+}  // namespace sim
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/RelaySim.h b/wpilibc/src/main/native/include/frc/simulation/RelaySim.h
index 99a8eef..5034885 100644
--- a/wpilibc/src/main/native/include/frc/simulation/RelaySim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/RelaySim.h
@@ -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.
 
 #pragma once
 
@@ -36,34 +33,107 @@
    */
   explicit RelaySim(int channel);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedForwardCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterInitializedForwardCallback(NotifyCallback callback,
+                                     bool initialNotify);
 
+  /**
+   * Check whether the forward direction has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitializedForward() const;
 
+  /**
+   * Define whether the forward direction has been initialized.
+   *
+   * @param initializedForward whether this object is initialized
+   */
   void SetInitializedForward(bool initializedForward);
 
-  std::unique_ptr<CallbackStore> RegisterInitializedReverseCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore>
+  RegisterInitializedReverseCallback(NotifyCallback callback,
+                                     bool initialNotify);
 
+  /**
+   * Check whether the reverse direction has been initialized.
+   *
+   * @return true if initialized
+   */
   bool GetInitializedReverse() const;
 
+  /**
+   * Define whether the reverse direction has been initialized.
+   *
+   * @param initializedReverse whether this object is initialized
+   */
   void SetInitializedReverse(bool initializedReverse);
 
-  std::unique_ptr<CallbackStore> RegisterForwardCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterForwardCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether the forward direction is active.
+   *
+   * @return true if active
+   */
   bool GetForward() const;
 
+  /**
+   * Set whether the forward direction is active.
+   *
+   * @param forward true to make active
+   */
   void SetForward(bool forward);
 
-  std::unique_ptr<CallbackStore> RegisterReverseCallback(
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterReverseCallback(
       NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether the reverse direction is active.
+   *
+   * @return true if active
+   */
   bool GetReverse() const;
 
+  /**
+   * Set whether the reverse direction is active.
+   *
+   * @param reverse true to make active
+   */
   void SetReverse(bool reverse);
 
+  /**
+   * Reset all simulation data.
+   */
   void ResetData();
 
  private:
diff --git a/wpilibc/src/main/native/include/frc/simulation/RoboRioSim.h b/wpilibc/src/main/native/include/frc/simulation/RoboRioSim.h
index 32eb462..1095106 100644
--- a/wpilibc/src/main/native/include/frc/simulation/RoboRioSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/RoboRioSim.h
@@ -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.
 
 #pragma once
 
@@ -14,120 +11,416 @@
 
 #include "frc/simulation/CallbackStore.h"
 
-namespace frc {
-namespace sim {
+namespace frc::sim {
 
 /**
- * Class to control a simulated RoboRIO.
+ * A utility class to control a simulated RoboRIO.
  */
 class RoboRioSim {
  public:
-  static std::unique_ptr<CallbackStore> RegisterFPGAButtonCallback(
-      NotifyCallback callback, bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterFPGAButtonCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Query the state of the FPGA button.
+   *
+   * @return the FPGA button state
+   */
   static bool GetFPGAButton();
 
+  /**
+   * Define the state of the FPGA button.
+   *
+   * @param fPGAButton the new state
+   */
   static void SetFPGAButton(bool fPGAButton);
 
-  static std::unique_ptr<CallbackStore> RegisterVInVoltageCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterVInVoltageCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the Vin voltage.
+   *
+   * @return the Vin voltage
+   */
   static units::volt_t GetVInVoltage();
 
+  /**
+   * Define the Vin voltage.
+   *
+   * @param vInVoltage the new voltage
+   */
   static void SetVInVoltage(units::volt_t vInVoltage);
 
-  static std::unique_ptr<CallbackStore> RegisterVInCurrentCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterVInCurrentCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the Vin current.
+   *
+   * @return the Vin current
+   */
   static units::ampere_t GetVInCurrent();
 
+  /**
+   * Define the Vin current.
+   *
+   * @param vInCurrent the new current
+   */
   static void SetVInCurrent(units::ampere_t vInCurrent);
 
-  static std::unique_ptr<CallbackStore> RegisterUserVoltage6VCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserVoltage6VCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the 6V rail voltage.
+   *
+   * @return the 6V rail voltage
+   */
   static units::volt_t GetUserVoltage6V();
 
+  /**
+   * Define the 6V rail voltage.
+   *
+   * @param userVoltage6V the new voltage
+   */
   static void SetUserVoltage6V(units::volt_t userVoltage6V);
 
-  static std::unique_ptr<CallbackStore> RegisterUserCurrent6VCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserCurrent6VCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the 6V rail current.
+   *
+   * @return the 6V rail current
+   */
   static units::ampere_t GetUserCurrent6V();
 
+  /**
+   * Define the 6V rail current.
+   *
+   * @param userCurrent6V the new current
+   */
   static void SetUserCurrent6V(units::ampere_t userCurrent6V);
 
-  static std::unique_ptr<CallbackStore> RegisterUserActive6VCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserActive6VCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the 6V rail active state.
+   *
+   * @return true if the 6V rail is active
+   */
   static bool GetUserActive6V();
 
+  /**
+   * Set the 6V rail active state.
+   *
+   * @param userActive6V true to make rail active
+   */
   static void SetUserActive6V(bool userActive6V);
 
-  static std::unique_ptr<CallbackStore> RegisterUserVoltage5VCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserVoltage5VCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the 5V rail voltage.
+   *
+   * @return the 5V rail voltage
+   */
   static units::volt_t GetUserVoltage5V();
 
+  /**
+   * Define the 5V rail voltage.
+   *
+   * @param userVoltage5V the new voltage
+   */
   static void SetUserVoltage5V(units::volt_t userVoltage5V);
 
-  static std::unique_ptr<CallbackStore> RegisterUserCurrent5VCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserCurrent5VCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the 5V rail current.
+   *
+   * @return the 5V rail current
+   */
   static units::ampere_t GetUserCurrent5V();
 
+  /**
+   * Define the 5V rail current.
+   *
+   * @param userCurrent5V the new current
+   */
   static void SetUserCurrent5V(units::ampere_t userCurrent5V);
 
-  static std::unique_ptr<CallbackStore> RegisterUserActive5VCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserActive5VCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the 5V rail active state.
+   *
+   * @return true if the 5V rail is active
+   */
   static bool GetUserActive5V();
 
+  /**
+   * Set the 5V rail active state.
+   *
+   * @param userActive5V true to make rail active
+   */
   static void SetUserActive5V(bool userActive5V);
 
-  static std::unique_ptr<CallbackStore> RegisterUserVoltage3V3Callback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserVoltage3V3Callback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the 3.3V rail voltage.
+   *
+   * @return the 3.3V rail voltage
+   */
   static units::volt_t GetUserVoltage3V3();
 
+  /**
+   * Define the 3.3V rail voltage.
+   *
+   * @param userVoltage3V3 the new voltage
+   */
   static void SetUserVoltage3V3(units::volt_t userVoltage3V3);
 
-  static std::unique_ptr<CallbackStore> RegisterUserCurrent3V3Callback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserCurrent3V3Callback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the 3.3V rail current.
+   *
+   * @return the 3.3V rail current
+   */
   static units::ampere_t GetUserCurrent3V3();
 
+  /**
+   * Define the 3.3V rail current.
+   *
+   * @param userCurrent3V3 the new current
+   */
   static void SetUserCurrent3V3(units::ampere_t userCurrent3V3);
 
-  static std::unique_ptr<CallbackStore> RegisterUserActive3V3Callback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserActive3V3Callback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the 3.3V rail active state.
+   *
+   * @return true if the 3.3V rail is active
+   */
   static bool GetUserActive3V3();
 
+  /**
+   * Set the 3.3V rail active state.
+   *
+   * @param userActive3V3 true to make rail active
+   */
   static void SetUserActive3V3(bool userActive3V3);
 
-  static std::unique_ptr<CallbackStore> RegisterUserFaults6VCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserFaults6VCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the 6V rail number of faults.
+   *
+   * @return number of faults
+   */
   static int GetUserFaults6V();
 
+  /**
+   * Set the 6V rail number of faults.
+   *
+   * @param userFaults6V number of faults
+   */
   static void SetUserFaults6V(int userFaults6V);
 
-  static std::unique_ptr<CallbackStore> RegisterUserFaults5VCallback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserFaults5VCallback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the 5V rail number of faults.
+   *
+   * @return number of faults
+   */
   static int GetUserFaults5V();
 
+  /**
+   * Set the 5V rail number of faults.
+   *
+   * @param userFaults5V number of faults
+   */
   static void SetUserFaults5V(int userFaults5V);
 
-  static std::unique_ptr<CallbackStore> RegisterUserFaults3V3Callback(
-      NotifyCallback callback, bool 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterUserFaults3V3Callback(NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Get the 3.3V rail number of faults.
+   *
+   * @return number of faults
+   */
   static int GetUserFaults3V3();
 
+  /**
+   * Set the 3.3V rail number of faults.
+   *
+   * @param userFaults3V3 number of faults
+   */
   static void SetUserFaults3V3(int 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] static std::unique_ptr<CallbackStore>
+  RegisterBrownoutVoltageCallback(NotifyCallback callback, bool initialNotify);
+
+  /**
+   * Measure the brownout voltage.
+   *
+   * @return the brownout voltage
+   */
+  static units::volt_t GetBrownoutVoltage();
+
+  /**
+   * Define the brownout voltage.
+   *
+   * @param brownoutVoltage the new voltage
+   */
+  static void SetBrownoutVoltage(units::volt_t brownoutVoltage);
+
+  /**
+   * Reset all simulation data.
+   */
   static void ResetData();
 };
-}  // namespace sim
-}  // namespace frc
+}  // namespace frc::sim
diff --git a/wpilibc/src/main/native/include/frc/simulation/SPIAccelerometerSim.h b/wpilibc/src/main/native/include/frc/simulation/SPIAccelerometerSim.h
index f2e3249..9d31bd0 100644
--- a/wpilibc/src/main/native/include/frc/simulation/SPIAccelerometerSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/SPIAccelerometerSim.h
@@ -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.
 
 #pragma once
 
@@ -11,51 +8,142 @@
 
 #include "frc/simulation/CallbackStore.h"
 
-namespace frc {
-namespace sim {
+namespace frc::sim {
 class SPIAccelerometerSim {
  public:
+  /**
+   * Construct a new simulation object.
+   *
+   * @param index the HAL index of the accelerometer
+   */
   explicit SPIAccelerometerSim(int index);
 
-  std::unique_ptr<CallbackStore> RegisterActiveCallback(NotifyCallback callback,
-                                                        bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterActiveCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check whether the accelerometer is active.
+   *
+   * @return true if active
+   */
   bool GetActive() const;
 
+  /**
+   * Define whether this accelerometer is active.
+   *
+   * @param active the new state
+   */
   void SetActive(bool active);
 
-  std::unique_ptr<CallbackStore> RegisterRangeCallback(NotifyCallback callback,
-                                                       bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterRangeCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Check the range of this accelerometer.
+   *
+   * @return the accelerometer range
+   */
   int GetRange() const;
 
+  /**
+   * Change the range of this accelerometer.
+   *
+   * @param range the new accelerometer range
+   */
   void SetRange(int range);
 
-  std::unique_ptr<CallbackStore> RegisterXCallback(NotifyCallback callback,
-                                                   bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterXCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the X axis value.
+   *
+   * @return the X axis measurement
+   */
   double GetX() const;
 
+  /**
+   * Change the X axis value of the accelerometer.
+   *
+   * @param x the new reading of the X axis
+   */
   void SetX(double x);
 
-  std::unique_ptr<CallbackStore> RegisterYCallback(NotifyCallback callback,
-                                                   bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterYCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the Y axis value.
+   *
+   * @return the Y axis measurement
+   */
   double GetY() const;
 
+  /**
+   * Change the Y axis value of the accelerometer.
+   *
+   * @param y the new reading of the Y axis
+   */
   void SetY(double y);
 
-  std::unique_ptr<CallbackStore> RegisterZCallback(NotifyCallback callback,
-                                                   bool initialNotify);
+  /**
+   * 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 CallbackStore object associated with this callback
+   */
+  [[nodiscard]] std::unique_ptr<CallbackStore> RegisterZCallback(
+      NotifyCallback callback, bool initialNotify);
 
+  /**
+   * Measure the Z axis value.
+   *
+   * @return the Z axis measurement
+   */
   double GetZ() const;
 
+  /**
+   * Change the Z axis value of the accelerometer.
+   *
+   * @param z the new reading of the Z axis
+   */
   void SetZ(double z);
 
+  /**
+   * Reset all simulation data of this object.
+   */
   void ResetData();
 
  private:
   int m_index;
 };
-}  // namespace sim
-}  // namespace frc
+}  // namespace frc::sim
diff --git a/wpilibc/src/main/native/include/frc/simulation/SimDeviceSim.h b/wpilibc/src/main/native/include/frc/simulation/SimDeviceSim.h
index 640cc0e..0a4e4d8 100644
--- a/wpilibc/src/main/native/include/frc/simulation/SimDeviceSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/SimDeviceSim.h
@@ -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.
 
 #pragma once
 
@@ -14,8 +11,7 @@
 #include <hal/SimDevice.h>
 #include <hal/simulation/SimDeviceData.h>
 
-namespace frc {
-namespace sim {
+namespace frc::sim {
 
 /**
  * Class to control the simulation side of a SimDevice.
@@ -29,28 +25,109 @@
    */
   explicit SimDeviceSim(const char* name);
 
+  /**
+   * Constructs a SimDeviceSim.
+   *
+   * @param name name of the SimDevice
+   * @param index device index number to append to name
+   */
+  SimDeviceSim(const char* name, int 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
+   */
+  SimDeviceSim(const char* name, int index, int channel);
+
+  /**
+   * Get the property object with the given name.
+   *
+   * @param name the property name
+   * @return the property object
+   */
   hal::SimValue GetValue(const char* name) const;
 
+  /**
+   * Get the property object with the given name.
+   *
+   * @param name the property name
+   * @return the property object
+   */
+  hal::SimInt GetInt(const char* name) const;
+
+  /**
+   * Get the property object with the given name.
+   *
+   * @param name the property name
+   * @return the property object
+   */
+  hal::SimLong GetLong(const char* name) const;
+
+  /**
+   * Get the property object with the given name.
+   *
+   * @param name the property name
+   * @return the property object
+   */
   hal::SimDouble GetDouble(const char* name) const;
 
+  /**
+   * Get the property object with the given name.
+   *
+   * @param name the property name
+   * @return the property object
+   */
   hal::SimEnum GetEnum(const char* name) const;
 
+  /**
+   * Get the property object with the given name.
+   *
+   * @param name the property name
+   * @return the property object
+   */
   hal::SimBoolean GetBoolean(const char* name) const;
 
+  /**
+   * Get all options for the given enum.
+   *
+   * @param val the enum
+   * @return names of the different values for that enum
+   */
   static std::vector<std::string> GetEnumOptions(hal::SimEnum val);
 
+  /**
+   * Get all properties.
+   *
+   * @param callback callback called for each property (SimValue).  Signature
+   *                 of the callback must be const char*, HAL_SimValueHandle,
+   *                 int, const HAL_Value*
+   */
   template <typename F>
   void EnumerateValues(F callback) const {
     return HALSIM_EnumerateSimValues(
         m_handle, &callback,
         [](const char* name, void* param, HAL_SimValueHandle handle,
-           HAL_Bool readonly, const struct HAL_Value* value) {
-          std::invoke(*static_cast<F*>(param), name, handle, readonly, value);
+           int direction, const struct HAL_Value* value) {
+          std::invoke(*static_cast<F*>(param), name, handle, direction, value);
         });
   }
 
-  operator HAL_SimDeviceHandle() const { return m_handle; }
+  /**
+   * Get the raw handle of this object.
+   *
+   * @return the handle used to refer to this object
+   */
+  operator HAL_SimDeviceHandle() const { return m_handle; }  // NOLINT
 
+  /**
+   * Get all sim devices with the given prefix.
+   *
+   * @param prefix the prefix to filter sim devices
+   * @param callback callback function to call for each sim device
+   */
   template <typename F>
   static void EnumerateDevices(const char* prefix, F callback) {
     return HALSIM_EnumerateSimDevices(
@@ -60,10 +137,12 @@
         });
   }
 
+  /**
+   * Reset all SimDevice data.
+   */
   static void ResetData();
 
  private:
   HAL_SimDeviceHandle m_handle;
 };
-}  // namespace sim
-}  // namespace frc
+}  // namespace frc::sim
diff --git a/wpilibc/src/main/native/include/frc/simulation/SimHooks.h b/wpilibc/src/main/native/include/frc/simulation/SimHooks.h
index 7690a4f..5d8a6b4 100644
--- a/wpilibc/src/main/native/include/frc/simulation/SimHooks.h
+++ b/wpilibc/src/main/native/include/frc/simulation/SimHooks.h
@@ -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.
 
 #pragma once
 
@@ -12,9 +9,13 @@
 #include <hal/HALBase.h>
 #include <units/time.h>
 
-namespace frc {
-namespace sim {
+namespace frc::sim {
 
+/**
+ * Override the HAL runtime type (simulated/real).
+ *
+ * @param type runtime type
+ */
 void SetRuntimeType(HAL_RuntimeType type);
 
 void WaitForProgramStart();
@@ -23,17 +24,40 @@
 
 bool GetProgramStarted();
 
+/**
+ * Restart the simulator time.
+ */
 void RestartTiming();
 
+/**
+ * Pause the simulator time.
+ */
 void PauseTiming();
 
+/**
+ * Resume the simulator time.
+ */
 void ResumeTiming();
 
+/**
+ * Check if the simulator time is paused.
+ *
+ * @return true if paused
+ */
 bool IsTimingPaused();
 
+/**
+ * Advance the simulator time and wait for all notifiers to run.
+ *
+ * @param delta the amount to advance (in seconds)
+ */
 void StepTiming(units::second_t delta);
 
+/**
+ * Advance the simulator time and return immediately.
+ *
+ * @param delta the amount to advance (in seconds)
+ */
 void StepTimingAsync(units::second_t delta);
 
-}  // namespace sim
-}  // namespace frc
+}  // namespace frc::sim
diff --git a/wpilibc/src/main/native/include/frc/simulation/SingleJointedArmSim.h b/wpilibc/src/main/native/include/frc/simulation/SingleJointedArmSim.h
index f8de822..4ff29cc 100644
--- a/wpilibc/src/main/native/include/frc/simulation/SingleJointedArmSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/SingleJointedArmSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -66,20 +63,34 @@
                       const std::array<double, 1>& measurementStdDevs = {0.0});
 
   /**
+   * Returns whether the arm would hit the lower limit.
+   *
+   * @param armAngle The arm height.
+   * @return Whether the arm would hit the lower limit.
+   */
+  bool WouldHitLowerLimit(units::radian_t armAngle) const;
+
+  /**
+   * Returns whether the arm would hit the upper limit.
+   *
+   * @param armAngle The arm height.
+   * @return Whether the arm would hit the upper limit.
+   */
+  bool WouldHitUpperLimit(units::radian_t armAngle) const;
+
+  /**
    * Returns whether the arm has hit the lower limit.
    *
-   * @param x The current arm state.
    * @return Whether the arm has hit the lower limit.
    */
-  bool HasHitLowerLimit(const Eigen::Matrix<double, 2, 1>& x) const;
+  bool HasHitLowerLimit() const;
 
   /**
    * Returns whether the arm has hit the upper limit.
    *
-   * @param x The current arm state.
    * @return Whether the arm has hit the upper limit.
    */
-  bool HasHitUpperLimit(const Eigen::Matrix<double, 2, 1>& x) const;
+  bool HasHitUpperLimit() const;
 
   /**
    * Returns the current arm angle.
@@ -103,7 +114,7 @@
   units::ampere_t GetCurrentDraw() const override;
 
   /**
-   * Sets the input voltage for the elevator.
+   * Sets the input voltage for the arm.
    *
    * @param voltage The input voltage.
    */
@@ -131,9 +142,9 @@
    * @param u           The system inputs (voltage).
    * @param dt          The time difference between controller updates.
    */
-  Eigen::Matrix<double, 2, 1> UpdateX(
-      const Eigen::Matrix<double, 2, 1>& currentXhat,
-      const Eigen::Matrix<double, 1, 1>& u, units::second_t dt) override;
+  Eigen::Vector<double, 2> UpdateX(const Eigen::Vector<double, 2>& currentXhat,
+                                   const Eigen::Vector<double, 1>& u,
+                                   units::second_t dt) override;
 
  private:
   units::meter_t m_r;
diff --git a/wpilibc/src/main/native/include/frc/simulation/UltrasonicSim.h b/wpilibc/src/main/native/include/frc/simulation/UltrasonicSim.h
new file mode 100644
index 0000000..efa9b37
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/simulation/UltrasonicSim.h
@@ -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.
+
+#pragma once
+
+#include <hal/SimDevice.h>
+#include <units/length.h>
+
+namespace frc {
+
+class Ultrasonic;
+
+namespace sim {
+
+/**
+ * Class to control a simulated ADXRS450 gyroscope.
+ */
+class UltrasonicSim {
+ public:
+  /**
+   * Constructs from a ADXRS450_Gyro object.
+   *
+   * @param gyro ADXRS450_Gyro to simulate
+   */
+  explicit UltrasonicSim(const Ultrasonic& gyro);
+
+  /**
+   * Sets if the range measurement is valid.
+   *
+   * @param isValid True if valid
+   */
+  void SetRangeValid(bool isValid);
+
+  /**
+   * Sets the range measurement
+   *
+   * @param range The range
+   */
+  void SetRange(units::meter_t range);
+
+ private:
+  hal::SimBoolean m_simRangeValid;
+  hal::SimDouble m_simRange;
+};
+
+}  // namespace sim
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/simulation/XboxControllerSim.h b/wpilibc/src/main/native/include/frc/simulation/XboxControllerSim.h
index d981111..e609ff0 100644
--- a/wpilibc/src/main/native/include/frc/simulation/XboxControllerSim.h
+++ b/wpilibc/src/main/native/include/frc/simulation/XboxControllerSim.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
@@ -34,27 +31,117 @@
    */
   explicit XboxControllerSim(int port);
 
-  void SetX(GenericHID::JoystickHand hand, double value);
+  /**
+   * Change the X axis value of the controller's left stick.
+   *
+   * @param value the new value
+   */
+  void SetLeftX(double value);
 
-  void SetY(GenericHID::JoystickHand hand, double value);
+  /**
+   * Change the X axis value of the controller's right stick.
+   *
+   * @param value the new value
+   */
+  void SetRightX(double value);
 
-  void SetTriggerAxis(GenericHID::JoystickHand hand, double value);
+  /**
+   * Change the Y axis value of the controller's left stick.
+   *
+   * @param value the new value
+   */
+  void SetLeftY(double value);
 
-  void SetBumper(GenericHID::JoystickHand hand, bool state);
+  /**
+   * Change the Y axis value of the controller's right stick.
+   *
+   * @param value the new value
+   */
+  void SetRightY(double value);
 
-  void SetStickButton(GenericHID::JoystickHand hand, bool state);
+  /**
+   * Change the left trigger axis value of the joystick.
+   *
+   * @param value the new value
+   */
+  void SetLeftTriggerAxis(double value);
 
-  void SetAButton(bool state);
+  /**
+   * Change the right trigger axis value of the joystick.
+   *
+   * @param value the new value
+   */
+  void SetRightTriggerAxis(double value);
 
-  void SetBButton(bool state);
+  /**
+   * Change the left bumper value of the joystick.
+   *
+   * @param value the new value
+   */
+  void SetLeftBumper(bool value);
 
-  void SetXButton(bool state);
+  /**
+   * Change the right bumper value of the joystick.
+   *
+   * @param value the new value
+   */
+  void SetRightBumper(bool value);
 
-  void SetYButton(bool state);
+  /**
+   * Change the left button value of the joystick.
+   *
+   * @param value the new value
+   */
+  void SetLeftStickButton(bool value);
 
-  void SetBackButton(bool state);
+  /**
+   * Change the right button value of the joystick.
+   *
+   * @param value the new value
+   */
+  void SetRightStickButton(bool value);
 
-  void SetStartButton(bool state);
+  /**
+   * Change the value of the A button.
+   *
+   * @param value the new value
+   */
+  void SetAButton(bool value);
+
+  /**
+   * Change the value of the B button.
+   *
+   * @param value the new value
+   */
+  void SetBButton(bool value);
+
+  /**
+   * Change the value of the X button.
+   *
+   * @param value the new value
+   */
+  void SetXButton(bool value);
+
+  /**
+   * Change the value of the Y button.
+   *
+   * @param value the new value
+   */
+  void SetYButton(bool value);
+
+  /**
+   * Change the value of the Back button.
+   *
+   * @param value the new value
+   */
+  void SetBackButton(bool value);
+
+  /**
+   * Change the value of the Start button.
+   *
+   * @param value the new value
+   */
+  void SetStartButton(bool value);
 };
 
 }  // namespace sim
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/Field2d.h b/wpilibc/src/main/native/include/frc/smartdashboard/Field2d.h
new file mode 100644
index 0000000..61d7a72
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/Field2d.h
@@ -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.
+
+#pragma once
+
+#include <memory>
+#include <string_view>
+#include <vector>
+
+#include <networktables/NTSendable.h>
+#include <networktables/NetworkTable.h>
+#include <networktables/NetworkTableEntry.h>
+#include <units/length.h>
+#include <wpi/mutex.h>
+#include <wpi/sendable/SendableHelper.h>
+
+#include "frc/geometry/Pose2d.h"
+#include "frc/geometry/Rotation2d.h"
+#include "frc/smartdashboard/FieldObject2d.h"
+
+namespace frc {
+
+/**
+ * 2D representation of game field for dashboards.
+ *
+ * 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,
+ * 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).
+ *
+ * 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.
+ *
+ * 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).
+ */
+class Field2d : public nt::NTSendable, public wpi::SendableHelper<Field2d> {
+ public:
+  using Entry = size_t;
+
+  Field2d();
+
+  Field2d(Field2d&& rhs);
+  Field2d& operator=(Field2d&& rhs);
+
+  /**
+   * Set the robot pose from a Pose object.
+   *
+   * @param pose 2D pose
+   */
+  void SetRobotPose(const Pose2d& pose);
+
+  /**
+   * Set the robot pose from x, y, and rotation.
+   *
+   * @param x X location
+   * @param y Y location
+   * @param rotation rotation
+   */
+  void SetRobotPose(units::meter_t x, units::meter_t y, Rotation2d rotation);
+
+  /**
+   * Get the robot pose.
+   *
+   * @return 2D pose
+   */
+  Pose2d GetRobotPose() const;
+
+  /**
+   * Get or create a field object.
+   *
+   * @return Field object
+   */
+  FieldObject2d* GetObject(std::string_view name);
+
+  /**
+   * Get the robot object.
+   *
+   * @return Field object for robot
+   */
+  FieldObject2d* GetRobotObject();
+
+  void InitSendable(nt::NTSendableBuilder& builder) override;
+
+ private:
+  std::shared_ptr<nt::NetworkTable> m_table;
+
+  mutable wpi::mutex m_mutex;
+  std::vector<std::unique_ptr<FieldObject2d>> m_objects;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/FieldObject2d.h b/wpilibc/src/main/native/include/frc/smartdashboard/FieldObject2d.h
new file mode 100644
index 0000000..2e41d84
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/FieldObject2d.h
@@ -0,0 +1,112 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <initializer_list>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include <networktables/NetworkTableEntry.h>
+#include <units/length.h>
+#include <wpi/SmallVector.h>
+#include <wpi/mutex.h>
+#include <wpi/span.h>
+
+#include "frc/geometry/Pose2d.h"
+#include "frc/geometry/Rotation2d.h"
+
+namespace frc {
+
+class Field2d;
+class Trajectory;
+
+/**
+ * Game field object on a Field2d.
+ */
+class FieldObject2d {
+  friend class Field2d;
+  struct private_init {};
+
+ public:
+  FieldObject2d(std::string_view name, const private_init&) : m_name{name} {}
+
+  FieldObject2d(FieldObject2d&& rhs);
+  FieldObject2d& operator=(FieldObject2d&& rhs);
+
+  /**
+   * Set the pose from a Pose object.
+   *
+   * @param pose 2D pose
+   */
+  void SetPose(const Pose2d& pose);
+
+  /**
+   * Set the pose from x, y, and rotation.
+   *
+   * @param x X location
+   * @param y Y location
+   * @param rotation rotation
+   */
+  void SetPose(units::meter_t x, units::meter_t y, Rotation2d rotation);
+
+  /**
+   * Get the pose.
+   *
+   * @return 2D pose, or 0,0,0 if unknown / does not exist
+   */
+  Pose2d GetPose() const;
+
+  /**
+   * Set multiple poses from an array of Pose objects.
+   * The total number of poses is limited to 85.
+   *
+   * @param poses array of 2D poses
+   */
+  void SetPoses(wpi::span<const Pose2d> poses);
+
+  /**
+   * Set multiple poses from an array of Pose objects.
+   * The total number of poses is limited to 85.
+   *
+   * @param poses array of 2D poses
+   */
+  void SetPoses(std::initializer_list<Pose2d> poses);
+
+  /**
+   * Sets poses from a trajectory.
+   *
+   * @param trajectory The trajectory from which poses should be added.
+   */
+  void SetTrajectory(const Trajectory& trajectory);
+
+  /**
+   * Get multiple poses.
+   *
+   * @param obj Object entry
+   * @return vector of 2D poses
+   */
+  std::vector<Pose2d> GetPoses() const;
+
+  /**
+   * Get multiple poses.
+   *
+   * @param out output SmallVector to hold 2D poses
+   * @return span referring to output SmallVector
+   */
+  wpi::span<const Pose2d> GetPoses(wpi::SmallVectorImpl<Pose2d>& out) const;
+
+ private:
+  void UpdateEntry(bool setDefault = false);
+  void UpdateFromEntry() const;
+
+  mutable wpi::mutex m_mutex;
+  std::string m_name;
+  nt::NetworkTableEntry m_entry;
+  mutable wpi::SmallVector<Pose2d, 1> m_poses;
+};
+
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/ListenerExecutor.h b/wpilibc/src/main/native/include/frc/smartdashboard/ListenerExecutor.h
index 9500278..cdfdafd 100644
--- a/wpilibc/src/main/native/include/frc/smartdashboard/ListenerExecutor.h
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/ListenerExecutor.h
@@ -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.
 
 #pragma once
 
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/Mechanism2d.h b/wpilibc/src/main/native/include/frc/smartdashboard/Mechanism2d.h
new file mode 100644
index 0000000..cbe25be
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/Mechanism2d.h
@@ -0,0 +1,87 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <networktables/NTSendable.h>
+#include <networktables/NetworkTableEntry.h>
+#include <wpi/StringMap.h>
+#include <wpi/mutex.h>
+#include <wpi/sendable/SendableHelper.h>
+
+#include "frc/smartdashboard/MechanismRoot2d.h"
+#include "frc/util/Color8Bit.h"
+
+namespace frc {
+
+/**
+ * Visual 2D representation of arms, elevators, and general mechanisms through
+ * a node-based API.
+ *
+ * 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.
+ *
+ * Except for the Mechanism2d container object, none of the objects should be
+ * passed or interacted with by value! Obtain pointers from factory methods such
+ * as Mechanism2d.GetRoot() and MechanismObject2d.Append<>(). The Mechanism2d
+ * container object owns the root nodes, and each node internally owns the nodes
+ * based on it. Beware not to let the Mechanism2d object out of scope - all
+ * nodes will be recursively destructed!
+ *
+ * @see MechanismObject2d
+ * @see MechanismLigament2d
+ * @see MechanismRoot2d
+ */
+class Mechanism2d : public nt::NTSendable,
+                    public wpi::SendableHelper<Mechanism2d> {
+ public:
+  /**
+   * Create a new Mechanism2d with the given dimensions and background color.
+   *
+   * The dimensions represent the canvas that all the nodes are drawn on. The
+   * default color is dark blue.
+   *
+   * @param width the width
+   * @param height the height
+   * @param backgroundColor the background color
+   */
+  Mechanism2d(double width, double height,
+              const Color8Bit& backgroundColor = {0, 0, 32});
+
+  /**
+   * 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 object, or the existing one with the given name.
+   */
+  MechanismRoot2d* GetRoot(std::string_view name, double x, double y);
+
+  /**
+   * Set the Mechanism2d background color.
+   *
+   * @param color the new background color
+   */
+  void SetBackgroundColor(const Color8Bit& color);
+
+  void InitSendable(nt::NTSendableBuilder& builder) override;
+
+ private:
+  double m_width;
+  double m_height;
+  char m_color[10];
+  mutable wpi::mutex m_mutex;
+  std::shared_ptr<nt::NetworkTable> m_table;
+  wpi::StringMap<std::unique_ptr<MechanismRoot2d>> m_roots;
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/MechanismLigament2d.h b/wpilibc/src/main/native/include/frc/smartdashboard/MechanismLigament2d.h
new file mode 100644
index 0000000..70abaa6
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/MechanismLigament2d.h
@@ -0,0 +1,88 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <memory>
+#include <string_view>
+
+#include <networktables/NetworkTableEntry.h>
+#include <units/angle.h>
+
+#include "frc/smartdashboard/MechanismObject2d.h"
+#include "frc/util/Color8Bit.h"
+
+namespace frc {
+
+/**
+ * Ligament node on a Mechanism2d.
+ *
+ * A ligament can have its length changed (like an elevator) or angle changed,
+ * like an arm.
+ *
+ * @see Mechanism2d
+ */
+class MechanismLigament2d : public MechanismObject2d {
+ public:
+  MechanismLigament2d(std::string_view name, double length,
+                      units::degree_t angle, double lineWidth = 6,
+                      const frc::Color8Bit& color = {235, 137, 52});
+
+  /**
+   * Set the ligament color.
+   *
+   * @param color the color of the line
+   */
+  void SetColor(const frc::Color8Bit& color);
+
+  /**
+   * Set the ligament's length.
+   *
+   * @param length the line length
+   */
+  void SetLength(double length);
+
+  /**
+   * Get the ligament length.
+   *
+   * @return the line length
+   */
+  double GetLength();
+
+  /**
+   * Set the ligament's angle relative to its parent.
+   *
+   * @param angle the angle
+   */
+  void SetAngle(units::degree_t angle);
+
+  /**
+   * Get the ligament's angle relative to its parent.
+   *
+   * @return the angle
+   */
+  double GetAngle();
+
+  /**
+   * Set the line thickness.
+   *
+   * @param lineWidth the line thickness
+   */
+  void SetLineWeight(double lineWidth);
+
+ protected:
+  void UpdateEntries(std::shared_ptr<nt::NetworkTable> table) override;
+
+ private:
+  void Flush();
+  double m_length;
+  nt::NetworkTableEntry m_lengthEntry;
+  double m_angle;
+  nt::NetworkTableEntry m_angleEntry;
+  double m_weight;
+  nt::NetworkTableEntry m_weightEntry;
+  char m_color[10];
+  nt::NetworkTableEntry m_colorEntry;
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/MechanismObject2d.h b/wpilibc/src/main/native/include/frc/smartdashboard/MechanismObject2d.h
new file mode 100644
index 0000000..c4185e7
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/MechanismObject2d.h
@@ -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.
+
+#pragma once
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+
+#include <networktables/NetworkTable.h>
+#include <wpi/StringMap.h>
+
+#include "frc/Errors.h"
+
+namespace frc {
+
+/**
+ * Common base class for all Mechanism2d node types.
+ *
+ * To append another node, call Append with the type of node and its
+ * construction parameters. None of the node types are designed to be
+ * constructed directly, and are owned by their parent node/container - obtain
+ * pointers from the Append function or similar factory methods.
+ *
+ * @see Mechanism2d.
+ */
+class MechanismObject2d {
+  friend class Mechanism2d;
+
+ protected:
+  explicit MechanismObject2d(std::string_view name);
+
+  /**
+   * Update all entries with new ones from a new table.
+   *
+   * @param table the new table.
+   */
+  virtual void UpdateEntries(std::shared_ptr<nt::NetworkTable> table) = 0;
+
+  mutable wpi::mutex m_mutex;
+
+ public:
+  virtual ~MechanismObject2d() = default;
+
+  /**
+   * Retrieve the object's name.
+   *
+   * @return the object's name relative to its parent.
+   */
+  const std::string& GetName() const;
+
+  /**
+   * Append a Mechanism object that is based on this one.
+   *
+   * @param name the name of the new object.
+   * @param args constructor arguments of the object type.
+   * @return the constructed and appended object, useful for variable
+   * assignments and call chaining.
+   * @throw if an object with the given name already exists.
+   */
+  template <typename T, typename... Args,
+            typename =
+                std::enable_if_t<std::is_convertible_v<T*, MechanismObject2d*>>>
+  T* Append(std::string_view name, Args&&... args) {
+    std::scoped_lock lock(m_mutex);
+    auto& obj = m_objects[name];
+    if (obj) {
+      throw FRC_MakeError(
+          err::Error,
+          "MechanismObject names must be unique! `{}` was inserted twice!",
+          name);
+    }
+    obj = std::make_unique<T>(name, std::forward<Args>(args)...);
+    T* ex = static_cast<T*>(obj.get());
+    if (m_table) {
+      ex->Update(m_table->GetSubTable(name));
+    }
+    return ex;
+  }
+
+ private:
+  std::string m_name;
+  wpi::StringMap<std::unique_ptr<MechanismObject2d>> m_objects;
+  std::shared_ptr<nt::NetworkTable> m_table;
+  void Update(std::shared_ptr<nt::NetworkTable> table);
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/MechanismRoot2d.h b/wpilibc/src/main/native/include/frc/smartdashboard/MechanismRoot2d.h
new file mode 100644
index 0000000..5072547
--- /dev/null
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/MechanismRoot2d.h
@@ -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.
+
+#pragma once
+
+#include <memory>
+#include <string_view>
+
+#include <networktables/NetworkTableEntry.h>
+
+#include "MechanismObject2d.h"
+
+namespace frc {
+
+/**
+ * Root Mechanism2d node.
+ *
+ * A root is the anchor point of other nodes (such as ligaments).
+ *
+ * Do not create objects of this class directly! Obtain pointers from the
+ * Mechanism2d.GetRoot() factory method.
+ *
+ * <p>Append other nodes by using Append().
+ */
+class MechanismRoot2d : private MechanismObject2d {
+  friend class Mechanism2d;
+  struct private_init {};
+
+ public:
+  MechanismRoot2d(std::string_view name, double x, double y,
+                  const private_init&);
+
+  /**
+   * Set the root's position.
+   *
+   * @param x new x coordinate
+   * @param y new y coordinate
+   */
+  void SetPosition(double x, double y);
+
+  using MechanismObject2d::GetName;
+
+  using MechanismObject2d::Append;
+
+ private:
+  void UpdateEntries(std::shared_ptr<nt::NetworkTable> table) override;
+  inline void Flush();
+  double m_x;
+  double m_y;
+  nt::NetworkTableEntry m_xEntry;
+  nt::NetworkTableEntry m_yEntry;
+};
+}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/Sendable.h b/wpilibc/src/main/native/include/frc/smartdashboard/Sendable.h
deleted file mode 100644
index 5000855..0000000
--- a/wpilibc/src/main/native/include/frc/smartdashboard/Sendable.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2011-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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-namespace frc {
-
-class SendableBuilder;
-
-/**
- * Interface for Sendable objects.
- */
-class Sendable {
- public:
-  virtual ~Sendable() = default;
-
-  /**
-   * Initializes this Sendable object.
-   *
-   * @param builder sendable builder
-   */
-  virtual void InitSendable(SendableBuilder& builder) = 0;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableBase.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableBase.h
deleted file mode 100644
index 98419b9..0000000
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableBase.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* 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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <wpi/deprecated.h>
-
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
-
-namespace frc {
-
-class SendableBase : public Sendable, public SendableHelper<SendableBase> {
- public:
-  /**
-   * Creates an instance of the sensor base
-   *
-   * @deprecated use Sendable and SendableHelper
-   *
-   * @param addLiveWindow if true, add this Sendable to LiveWindow
-   */
-  WPI_DEPRECATED("use Sendable and SendableHelper")
-  explicit SendableBase(bool addLiveWindow = true);
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilder.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilder.h
deleted file mode 100644
index 3f5f892..0000000
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilder.h
+++ /dev/null
@@ -1,222 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <networktables/NetworkTableEntry.h>
-#include <networktables/NetworkTableValue.h>
-#include <wpi/ArrayRef.h>
-#include <wpi/SmallVector.h>
-#include <wpi/Twine.h>
-
-namespace frc {
-
-class SendableBuilder {
- public:
-  virtual ~SendableBuilder() = default;
-
-  /**
-   * Set the string representation of the named data type that will be used
-   * by the smart dashboard for this sendable.
-   *
-   * @param type    data type
-   */
-  virtual void SetSmartDashboardType(const wpi::Twine& type) = 0;
-
-  /**
-   * 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
-   */
-  virtual void SetActuator(bool value) = 0;
-
-  /**
-   * 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
-   */
-  virtual void SetSafeState(std::function<void()> func) = 0;
-
-  /**
-   * 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
-   */
-  virtual void SetUpdateTable(std::function<void()> func) = 0;
-
-  /**
-   * 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
-   */
-  virtual nt::NetworkTableEntry GetEntry(const wpi::Twine& key) = 0;
-
-  /**
-   * Add a boolean property.
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddBooleanProperty(const wpi::Twine& key,
-                                  std::function<bool()> getter,
-                                  std::function<void(bool)> setter) = 0;
-
-  /**
-   * Add a double property.
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddDoubleProperty(const wpi::Twine& key,
-                                 std::function<double()> getter,
-                                 std::function<void(double)> setter) = 0;
-
-  /**
-   * Add a string property.
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddStringProperty(
-      const wpi::Twine& key, std::function<std::string()> getter,
-      std::function<void(wpi::StringRef)> setter) = 0;
-
-  /**
-   * Add a boolean array property.
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddBooleanArrayProperty(
-      const wpi::Twine& key, std::function<std::vector<int>()> getter,
-      std::function<void(wpi::ArrayRef<int>)> setter) = 0;
-
-  /**
-   * Add a double array property.
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddDoubleArrayProperty(
-      const wpi::Twine& key, std::function<std::vector<double>()> getter,
-      std::function<void(wpi::ArrayRef<double>)> setter) = 0;
-
-  /**
-   * Add a string array property.
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddStringArrayProperty(
-      const wpi::Twine& key, std::function<std::vector<std::string>()> getter,
-      std::function<void(wpi::ArrayRef<std::string>)> setter) = 0;
-
-  /**
-   * Add a raw property.
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddRawProperty(const wpi::Twine& key,
-                              std::function<std::string()> getter,
-                              std::function<void(wpi::StringRef)> setter) = 0;
-
-  /**
-   * Add a NetworkTableValue property.
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddValueProperty(
-      const wpi::Twine& key, std::function<std::shared_ptr<nt::Value>()> getter,
-      std::function<void(std::shared_ptr<nt::Value>)> setter) = 0;
-
-  /**
-   * Add a string property (SmallString form).
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddSmallStringProperty(
-      const wpi::Twine& key,
-      std::function<wpi::StringRef(wpi::SmallVectorImpl<char>& buf)> getter,
-      std::function<void(wpi::StringRef)> setter) = 0;
-
-  /**
-   * Add a boolean array property (SmallVector form).
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddSmallBooleanArrayProperty(
-      const wpi::Twine& key,
-      std::function<wpi::ArrayRef<int>(wpi::SmallVectorImpl<int>& buf)> getter,
-      std::function<void(wpi::ArrayRef<int>)> setter) = 0;
-
-  /**
-   * Add a double array property (SmallVector form).
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddSmallDoubleArrayProperty(
-      const wpi::Twine& key,
-      std::function<wpi::ArrayRef<double>(wpi::SmallVectorImpl<double>& buf)>
-          getter,
-      std::function<void(wpi::ArrayRef<double>)> setter) = 0;
-
-  /**
-   * Add a string array property (SmallVector form).
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddSmallStringArrayProperty(
-      const wpi::Twine& key,
-      std::function<
-          wpi::ArrayRef<std::string>(wpi::SmallVectorImpl<std::string>& buf)>
-          getter,
-      std::function<void(wpi::ArrayRef<std::string>)> setter) = 0;
-
-  /**
-   * Add a raw property (SmallVector form).
-   *
-   * @param key     property name
-   * @param getter  getter function (returns current value)
-   * @param setter  setter function (sets new value)
-   */
-  virtual void AddSmallRawProperty(
-      const wpi::Twine& key,
-      std::function<wpi::StringRef(wpi::SmallVectorImpl<char>& buf)> getter,
-      std::function<void(wpi::StringRef)> setter) = 0;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilderImpl.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilderImpl.h
index e5dea44..36830f6 100644
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilderImpl.h
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/SendableBuilderImpl.h
@@ -1,30 +1,26 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <functional>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
+#include <networktables/NTSendableBuilder.h>
 #include <networktables/NetworkTable.h>
 #include <networktables/NetworkTableEntry.h>
 #include <networktables/NetworkTableValue.h>
-#include <wpi/ArrayRef.h>
 #include <wpi/SmallVector.h>
-#include <wpi/Twine.h>
-
-#include "frc/smartdashboard/SendableBuilder.h"
+#include <wpi/span.h>
 
 namespace frc {
 
-class SendableBuilderImpl : public SendableBuilder {
+class SendableBuilderImpl : public nt::NTSendableBuilder {
  public:
   SendableBuilderImpl() = default;
   ~SendableBuilderImpl() override = default;
@@ -43,13 +39,13 @@
    * Get the network table.
    * @return The network table
    */
-  std::shared_ptr<nt::NetworkTable> GetTable();
+  std::shared_ptr<nt::NetworkTable> GetTable() override;
 
   /**
    * Return whether this sendable has an associated table.
    * @return True if it has a table, false if not.
    */
-  bool HasTable() const;
+  bool IsPublished() const override;
 
   /**
    * Return whether this sendable should be treated as an actuator.
@@ -60,7 +56,7 @@
   /**
    * Update the network table values by calling the getters for all properties.
    */
-  void UpdateTable();
+  void Update() override;
 
   /**
    * Hook setters for all properties.
@@ -87,75 +83,75 @@
   /**
    * Clear properties.
    */
-  void ClearProperties();
+  void ClearProperties() override;
 
-  void SetSmartDashboardType(const wpi::Twine& type) override;
+  void SetSmartDashboardType(std::string_view type) override;
   void SetActuator(bool value) override;
   void SetSafeState(std::function<void()> func) override;
   void SetUpdateTable(std::function<void()> func) override;
-  nt::NetworkTableEntry GetEntry(const wpi::Twine& key) override;
+  nt::NetworkTableEntry GetEntry(std::string_view key) override;
 
-  void AddBooleanProperty(const wpi::Twine& key, std::function<bool()> getter,
+  void AddBooleanProperty(std::string_view key, std::function<bool()> getter,
                           std::function<void(bool)> setter) override;
 
-  void AddDoubleProperty(const wpi::Twine& key, std::function<double()> getter,
+  void AddDoubleProperty(std::string_view key, std::function<double()> getter,
                          std::function<void(double)> setter) override;
 
-  void AddStringProperty(const wpi::Twine& key,
+  void AddStringProperty(std::string_view key,
                          std::function<std::string()> getter,
-                         std::function<void(wpi::StringRef)> setter) override;
+                         std::function<void(std::string_view)> setter) override;
 
   void AddBooleanArrayProperty(
-      const wpi::Twine& key, std::function<std::vector<int>()> getter,
-      std::function<void(wpi::ArrayRef<int>)> setter) override;
+      std::string_view key, std::function<std::vector<int>()> getter,
+      std::function<void(wpi::span<const int>)> setter) override;
 
   void AddDoubleArrayProperty(
-      const wpi::Twine& key, std::function<std::vector<double>()> getter,
-      std::function<void(wpi::ArrayRef<double>)> setter) override;
+      std::string_view key, std::function<std::vector<double>()> getter,
+      std::function<void(wpi::span<const double>)> setter) override;
 
   void AddStringArrayProperty(
-      const wpi::Twine& key, std::function<std::vector<std::string>()> getter,
-      std::function<void(wpi::ArrayRef<std::string>)> setter) override;
+      std::string_view key, std::function<std::vector<std::string>()> getter,
+      std::function<void(wpi::span<const std::string>)> setter) override;
 
-  void AddRawProperty(const wpi::Twine& key,
-                      std::function<std::string()> getter,
-                      std::function<void(wpi::StringRef)> setter) override;
+  void AddRawProperty(std::string_view key, std::function<std::string()> getter,
+                      std::function<void(std::string_view)> setter) override;
 
   void AddValueProperty(
-      const wpi::Twine& key, std::function<std::shared_ptr<nt::Value>()> getter,
+      std::string_view key, std::function<std::shared_ptr<nt::Value>()> getter,
       std::function<void(std::shared_ptr<nt::Value>)> setter) override;
 
   void AddSmallStringProperty(
-      const wpi::Twine& key,
-      std::function<wpi::StringRef(wpi::SmallVectorImpl<char>& buf)> getter,
-      std::function<void(wpi::StringRef)> setter) override;
+      std::string_view key,
+      std::function<std::string_view(wpi::SmallVectorImpl<char>& buf)> getter,
+      std::function<void(std::string_view)> setter) override;
 
   void AddSmallBooleanArrayProperty(
-      const wpi::Twine& key,
-      std::function<wpi::ArrayRef<int>(wpi::SmallVectorImpl<int>& buf)> getter,
-      std::function<void(wpi::ArrayRef<int>)> setter) override;
+      std::string_view key,
+      std::function<wpi::span<const int>(wpi::SmallVectorImpl<int>& buf)>
+          getter,
+      std::function<void(wpi::span<const int>)> setter) override;
 
   void AddSmallDoubleArrayProperty(
-      const wpi::Twine& key,
-      std::function<wpi::ArrayRef<double>(wpi::SmallVectorImpl<double>& buf)>
+      std::string_view key,
+      std::function<wpi::span<const double>(wpi::SmallVectorImpl<double>& buf)>
           getter,
-      std::function<void(wpi::ArrayRef<double>)> setter) override;
+      std::function<void(wpi::span<const double>)> setter) override;
 
   void AddSmallStringArrayProperty(
-      const wpi::Twine& key,
+      std::string_view key,
       std::function<
-          wpi::ArrayRef<std::string>(wpi::SmallVectorImpl<std::string>& buf)>
+          wpi::span<const std::string>(wpi::SmallVectorImpl<std::string>& buf)>
           getter,
-      std::function<void(wpi::ArrayRef<std::string>)> setter) override;
+      std::function<void(wpi::span<const std::string>)> setter) override;
 
   void AddSmallRawProperty(
-      const wpi::Twine& key,
-      std::function<wpi::StringRef(wpi::SmallVectorImpl<char>& buf)> getter,
-      std::function<void(wpi::StringRef)> setter) override;
+      std::string_view key,
+      std::function<std::string_view(wpi::SmallVectorImpl<char>& buf)> getter,
+      std::function<void(std::string_view)> setter) override;
 
  private:
   struct Property {
-    Property(nt::NetworkTable& table, const wpi::Twine& key)
+    Property(nt::NetworkTable& table, std::string_view key)
         : entry(table.GetEntry(key)) {}
 
     Property(const Property&) = delete;
@@ -183,8 +179,9 @@
     ~Property() { StopListener(); }
 
     void StartListener() {
-      if (entry && listener == 0 && createListener)
+      if (entry && listener == 0 && createListener) {
         listener = createListener(entry);
+      }
     }
 
     void StopListener() {
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooser.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooser.h
index b370fc0..b693762 100644
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooser.h
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooser.h
@@ -1,19 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2011-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.
 
 #pragma once
 
 #include <memory>
+#include <string_view>
 
 #include <wpi/StringMap.h>
-#include <wpi/StringRef.h>
 #include <wpi/deprecated.h>
 
-#include "frc/smartdashboard/SendableBuilder.h"
 #include "frc/smartdashboard/SendableChooserBase.h"
 
 namespace frc {
@@ -45,27 +41,21 @@
   static std::weak_ptr<U> _unwrap_smart_ptr(const std::shared_ptr<U>& value);
 
  public:
-  ~SendableChooser() override = default;
   SendableChooser() = default;
+  ~SendableChooser() override = default;
   SendableChooser(SendableChooser&& rhs) = default;
   SendableChooser& operator=(SendableChooser&& rhs) = default;
 
-  void AddOption(wpi::StringRef name, T object);
-  void SetDefaultOption(wpi::StringRef name, T object);
-
   /**
    * Adds the given object to the list of options.
    *
    * On the SmartDashboard on the desktop, the object will appear as the given
    * name.
    *
-   * @deprecated use AddOption(wpi::StringRef name, T object) instead.
-   *
    * @param name   the name of the option
    * @param object the option
    */
-  WPI_DEPRECATED("use AddOption() instead")
-  void AddObject(wpi::StringRef name, T object) { AddOption(name, object); }
+  void AddOption(std::string_view name, T object);
 
   /**
    * Add the given object to the list of options and marks it as the default.
@@ -73,19 +63,55 @@
    * Functionally, this is very close to AddOption() except that it will use
    * this as the default option if none other is explicitly selected.
    *
-   * @deprecated use SetDefaultOption(wpi::StringRef name, T object) instead.
+   * @param name   the name of the option
+   * @param object the option
+   */
+  void SetDefaultOption(std::string_view name, T object);
+
+  /**
+   * Adds the given object to the list of options.
+   *
+   * On the SmartDashboard on the desktop, the object will appear as the given
+   * name.
+   *
+   * @deprecated use AddOption(std::string_view name, T object) instead.
+   *
+   * @param name   the name of the option
+   * @param object the option
+   */
+  WPI_DEPRECATED("use AddOption() instead")
+  void AddObject(std::string_view name, T object) { AddOption(name, object); }
+
+  /**
+   * Add the given object to the list of options and marks it as the default.
+   *
+   * Functionally, this is very close to AddOption() except that it will use
+   * this as the default option if none other is explicitly selected.
+   *
+   * @deprecated use SetDefaultOption(std::string_view name, T object) instead.
    *
    * @param name   the name of the option
    * @param object the option
    */
   WPI_DEPRECATED("use SetDefaultOption() instead")
-  void AddDefault(wpi::StringRef name, T object) {
+  void AddDefault(std::string_view name, T object) {
     SetDefaultOption(name, object);
   }
 
+  /**
+   * Returns a copy of the selected option (a raw pointer U* if T =
+   * std::unique_ptr<U> or a std::weak_ptr<U> if T = std::shared_ptr<U>).
+   *
+   * If there is none selected, it will return the default. If there is none
+   * selected and no default, then it will return a value-initialized instance.
+   * For integer types, this is 0. For container types like std::string, this is
+   * an empty string.
+   *
+   * @return The option selected
+   */
   auto GetSelected() -> decltype(_unwrap_smart_ptr(m_choices[""]));
 
-  void InitSendable(SendableBuilder& builder) override;
+  void InitSendable(nt::NTSendableBuilder& builder) override;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooser.inc b/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooser.inc
index 57e2828..25e2551 100644
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooser.inc
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooser.inc
@@ -1,69 +1,42 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2011-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.
 
 #pragma once
 
 #include <algorithm>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
-#include <wpi/StringRef.h>
+#include <networktables/NTSendableBuilder.h>
+
+#include "frc/smartdashboard/SendableChooser.h"
 
 namespace frc {
 
-/**
- * Adds the given object to the list of options.
- *
- * On the SmartDashboard on the desktop, the object will appear as the given
- * name.
- *
- * @param name   the name of the option
- * @param object the option
- */
 template <class T>
-void SendableChooser<T>::AddOption(wpi::StringRef name, T object) {
+void SendableChooser<T>::AddOption(std::string_view name, T object) {
   m_choices[name] = std::move(object);
 }
 
-/**
- * Add the given object to the list of options and marks it as the default.
- *
- * Functionally, this is very close to AddOption() except that it will use this
- * as the default option if none other is explicitly selected.
- *
- * @param name   the name of the option
- * @param object the option
- */
 template <class T>
-void SendableChooser<T>::SetDefaultOption(wpi::StringRef name, T object) {
+void SendableChooser<T>::SetDefaultOption(std::string_view name, T object) {
   m_defaultChoice = name;
   AddOption(name, std::move(object));
 }
 
-/**
- * Returns a copy of the selected option (a raw pointer U* if T =
- * std::unique_ptr<U> or a std::weak_ptr<U> if T = std::shared_ptr<U>).
- *
- * If there is none selected, it will return the default. If there is none
- * selected and no default, then it will return a value-initialized instance.
- * For integer types, this is 0. For container types like std::string, this is
- * an empty string.
- *
- * @return The option selected
- */
 template <class T>
 auto SendableChooser<T>::GetSelected()
     -> decltype(_unwrap_smart_ptr(m_choices[""])) {
   std::string selected = m_defaultChoice;
   {
     std::scoped_lock lock(m_mutex);
-    if (m_haveSelected) selected = m_selected;
+    if (m_haveSelected) {
+      selected = m_selected;
+    }
   }
   if (selected.empty()) {
     return decltype(_unwrap_smart_ptr(m_choices[""])){};
@@ -73,15 +46,15 @@
 }
 
 template <class T>
-void SendableChooser<T>::InitSendable(SendableBuilder& builder) {
+void SendableChooser<T>::InitSendable(nt::NTSendableBuilder& builder) {
   builder.SetSmartDashboardType("String Chooser");
   builder.GetEntry(kInstance).SetDouble(m_instance);
   builder.AddStringArrayProperty(
       kOptions,
-      [=]() {
+      [=] {
         std::vector<std::string> keys;
         for (const auto& choice : m_choices) {
-          keys.push_back(choice.first());
+          keys.emplace_back(choice.first());
         }
 
         // Unlike std::map, wpi::StringMap elements
@@ -93,17 +66,17 @@
       nullptr);
   builder.AddSmallStringProperty(
       kDefault,
-      [=](wpi::SmallVectorImpl<char>&) -> wpi::StringRef {
+      [=](wpi::SmallVectorImpl<char>&) -> std::string_view {
         return m_defaultChoice;
       },
       nullptr);
   builder.AddSmallStringProperty(
       kActive,
-      [=](wpi::SmallVectorImpl<char>& buf) -> wpi::StringRef {
+      [=](wpi::SmallVectorImpl<char>& buf) -> std::string_view {
         std::scoped_lock lock(m_mutex);
         if (m_haveSelected) {
           buf.assign(m_selected.begin(), m_selected.end());
-          return wpi::StringRef(buf.data(), buf.size());
+          return {buf.data(), buf.size()};
         } else {
           return m_defaultChoice;
         }
@@ -113,11 +86,13 @@
     std::scoped_lock lock(m_mutex);
     m_activeEntries.emplace_back(builder.GetEntry(kActive));
   }
-  builder.AddStringProperty(kSelected, nullptr, [=](wpi::StringRef val) {
+  builder.AddStringProperty(kSelected, nullptr, [=](std::string_view val) {
     std::scoped_lock lock(m_mutex);
     m_haveSelected = true;
     m_selected = val;
-    for (auto& entry : m_activeEntries) entry.SetString(val);
+    for (auto& entry : m_activeEntries) {
+      entry.SetString(val);
+    }
   });
 }
 
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooserBase.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooserBase.h
index 2a5f5ab..78f891a 100644
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooserBase.h
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/SendableChooserBase.h
@@ -1,21 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <atomic>
 #include <string>
 
+#include <networktables/NTSendable.h>
 #include <networktables/NetworkTableEntry.h>
 #include <wpi/SmallVector.h>
 #include <wpi/mutex.h>
-
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+#include <wpi/sendable/SendableHelper.h>
 
 namespace frc {
 
@@ -25,8 +21,8 @@
  * It contains static, non-templated variables to avoid their duplication in the
  * template class.
  */
-class SendableChooserBase : public Sendable,
-                            public SendableHelper<SendableChooserBase> {
+class SendableChooserBase : public nt::NTSendable,
+                            public wpi::SendableHelper<SendableChooserBase> {
  public:
   SendableChooserBase();
   ~SendableChooserBase() override = default;
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableHelper.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableHelper.h
deleted file mode 100644
index 1f39216..0000000
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableHelper.h
+++ /dev/null
@@ -1,179 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include <wpi/Twine.h>
-#include <wpi/deprecated.h>
-
-#include "frc/smartdashboard/SendableRegistry.h"
-
-namespace frc {
-
-/**
- * A helper class for use with objects that add themselves to SendableRegistry.
- * It takes care of properly calling Move() and Remove() on move and
- * destruction.  No action is taken if the object is copied.
- * Use public inheritance with CRTP when using this class.
- * @tparam CRTP derived class
- */
-template <typename Derived>
-class SendableHelper {
- public:
-  SendableHelper(const SendableHelper& rhs) = default;
-  SendableHelper& operator=(const SendableHelper& rhs) = default;
-
-  SendableHelper(SendableHelper&& rhs) {
-    // it is safe to call Move() multiple times with the same rhs
-    SendableRegistry::GetInstance().Move(static_cast<Derived*>(this),
-                                         static_cast<Derived*>(&rhs));
-  }
-
-  SendableHelper& operator=(SendableHelper&& rhs) {
-    // it is safe to call Move() multiple times with the same rhs
-    SendableRegistry::GetInstance().Move(static_cast<Derived*>(this),
-                                         static_cast<Derived*>(&rhs));
-    return *this;
-  }
-
-  /**
-   * Gets the name of this Sendable object.
-   *
-   * @deprecated use SendableRegistry::GetName()
-   *
-   * @return Name
-   */
-  WPI_DEPRECATED("use SendableRegistry::GetName()")
-  std::string GetName() const {
-    return SendableRegistry::GetInstance().GetName(
-        static_cast<const Derived*>(this));
-  }
-
-  /**
-   * Sets the name of this Sendable object.
-   *
-   * @deprecated use SendableRegistry::SetName()
-   *
-   * @param name name
-   */
-  WPI_DEPRECATED("use SendableRegistry::SetName()")
-  void SetName(const wpi::Twine& name) {
-    SendableRegistry::GetInstance().SetName(static_cast<Derived*>(this), name);
-  }
-
-  /**
-   * Sets both the subsystem name and device name of this Sendable object.
-   *
-   * @deprecated use SendableRegistry::SetName()
-   *
-   * @param subsystem subsystem name
-   * @param name device name
-   */
-  WPI_DEPRECATED("use SendableRegistry::SetName()")
-  void SetName(const wpi::Twine& subsystem, const wpi::Twine& name) {
-    SendableRegistry::GetInstance().SetName(static_cast<Derived*>(this),
-                                            subsystem, name);
-  }
-
-  /**
-   * Gets the subsystem name of this Sendable object.
-   *
-   * @deprecated use SendableRegistry::GetSubsystem().
-   *
-   * @return Subsystem name
-   */
-  WPI_DEPRECATED("use SendableRegistry::GetSubsystem()")
-  std::string GetSubsystem() const {
-    return SendableRegistry::GetInstance().GetSubsystem(
-        static_cast<const Derived*>(this));
-  }
-
-  /**
-   * Sets the subsystem name of this Sendable object.
-   *
-   * @deprecated use SendableRegistry::SetSubsystem()
-   *
-   * @param subsystem subsystem name
-   */
-  WPI_DEPRECATED("use SendableRegistry::SetSubsystem()")
-  void SetSubsystem(const wpi::Twine& subsystem) {
-    SendableRegistry::GetInstance().SetSubsystem(static_cast<Derived*>(this),
-                                                 subsystem);
-  }
-
- protected:
-  /**
-   * Add a child component.
-   *
-   * @deprecated use SendableRegistry::AddChild()
-   *
-   * @param child child component
-   */
-  WPI_DEPRECATED("use SendableRegistry::AddChild()")
-  void AddChild(std::shared_ptr<Sendable> child) {
-    SendableRegistry::GetInstance().AddChild(static_cast<Derived*>(this),
-                                             child.get());
-  }
-
-  /**
-   * Add a child component.
-   *
-   * @deprecated use SendableRegistry::AddChild()
-   *
-   * @param child child component
-   */
-  WPI_DEPRECATED("use SendableRegistry::AddChild()")
-  void AddChild(void* child) {
-    SendableRegistry::GetInstance().AddChild(static_cast<Derived*>(this),
-                                             child);
-  }
-
-  /**
-   * Sets the name of the sensor with a channel number.
-   *
-   * @deprecated use SendableRegistry::SetName()
-   *
-   * @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
-   */
-  WPI_DEPRECATED("use SendableRegistry::SetName()")
-  void SetName(const wpi::Twine& moduleType, int channel) {
-    SendableRegistry::GetInstance().SetName(static_cast<Derived*>(this),
-                                            moduleType, channel);
-  }
-
-  /**
-   * Sets the name of the sensor with a module and channel number.
-   *
-   * @deprecated use SendableRegistry::SetName()
-   *
-   * @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)
-   */
-  WPI_DEPRECATED("use SendableRegistry::SetName()")
-  void SetName(const wpi::Twine& moduleType, int moduleNumber, int channel) {
-    SendableRegistry::GetInstance().SetName(static_cast<Derived*>(this),
-                                            moduleType, moduleNumber, channel);
-  }
-
- protected:
-  SendableHelper() = default;
-
-  ~SendableHelper() {
-    // it is safe to call Remove() multiple times with the same object
-    SendableRegistry::GetInstance().Remove(static_cast<Derived*>(this));
-  }
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SendableRegistry.h b/wpilibc/src/main/native/include/frc/smartdashboard/SendableRegistry.h
deleted file mode 100644
index 78dabc6..0000000
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SendableRegistry.h
+++ /dev/null
@@ -1,341 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include <networktables/NetworkTable.h>
-#include <wpi/STLExtras.h>
-#include <wpi/Twine.h>
-
-namespace frc {
-
-class Sendable;
-class SendableBuilderImpl;
-
-/**
- * The SendableRegistry class is the public interface for registering sensors
- * and actuators for use on dashboards and LiveWindow.
- */
-class SendableRegistry {
- public:
-  SendableRegistry(const SendableRegistry&) = delete;
-  SendableRegistry& operator=(const SendableRegistry&) = delete;
-
-  using UID = size_t;
-
-  /**
-   * Gets an instance of the SendableRegistry class.
-   *
-   * This is a singleton to guarantee that there is only a single instance
-   * regardless of how many times GetInstance is called.
-   */
-  static SendableRegistry& GetInstance();
-
-  /**
-   * Adds an object to the registry.
-   *
-   * @param sendable object to add
-   * @param name component name
-   */
-  void Add(Sendable* sendable, const wpi::Twine& 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
-   */
-  void Add(Sendable* sendable, const wpi::Twine& moduleType, int 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
-   */
-  void Add(Sendable* sendable, const wpi::Twine& moduleType, int moduleNumber,
-           int channel);
-
-  /**
-   * Adds an object to the registry.
-   *
-   * @param sendable object to add
-   * @param subsystem subsystem name
-   * @param name component name
-   */
-  void Add(Sendable* sendable, const wpi::Twine& subsystem,
-           const wpi::Twine& name);
-
-  /**
-   * Adds an object to the registry and LiveWindow.
-   *
-   * @param sendable object to add
-   * @param name component name
-   */
-  void AddLW(Sendable* sendable, const wpi::Twine& 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
-   */
-  void AddLW(Sendable* sendable, const wpi::Twine& moduleType, int 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
-   */
-  void AddLW(Sendable* sendable, const wpi::Twine& moduleType, int moduleNumber,
-             int channel);
-
-  /**
-   * Adds an object to the registry and LiveWindow.
-   *
-   * @param sendable object to add
-   * @param subsystem subsystem name
-   * @param name component name
-   */
-  void AddLW(Sendable* sendable, const wpi::Twine& subsystem,
-             const wpi::Twine& name);
-
-  /**
-   * 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
-   */
-  void AddChild(Sendable* parent, Sendable* child);
-
-  /**
-   * 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
-   */
-  void AddChild(Sendable* parent, void* child);
-
-  /**
-   * Removes an object from the registry.
-   *
-   * @param sendable object to remove
-   * @return true if the object was removed; false if it was not present
-   */
-  bool Remove(Sendable* sendable);
-
-  /**
-   * Moves an object in the registry (for use in move constructors/assignments).
-   *
-   * @param to new object
-   * @param from old object
-   */
-  void Move(Sendable* to, Sendable* from);
-
-  /**
-   * Determines if an object is in the registry.
-   *
-   * @param sendable object to check
-   * @return True if in registry, false if not.
-   */
-  bool Contains(const Sendable* sendable) const;
-
-  /**
-   * Gets the name of an object.
-   *
-   * @param sendable object
-   * @return Name (empty if object is not in registry)
-   */
-  std::string GetName(const Sendable* sendable) const;
-
-  /**
-   * Sets the name of an object.
-   *
-   * @param sendable object
-   * @param name name
-   */
-  void SetName(Sendable* sendable, const wpi::Twine& 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
-   */
-  void SetName(Sendable* sendable, const wpi::Twine& moduleType, int 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
-   */
-  void SetName(Sendable* sendable, const wpi::Twine& moduleType,
-               int moduleNumber, int channel);
-
-  /**
-   * Sets both the subsystem name and device name of an object.
-   *
-   * @param sendable object
-   * @param subsystem subsystem name
-   * @param name device name
-   */
-  void SetName(Sendable* sendable, const wpi::Twine& subsystem,
-               const wpi::Twine& name);
-
-  /**
-   * Gets the subsystem name of an object.
-   *
-   * @param sendable object
-   * @return Subsystem name (empty if object is not in registry)
-   */
-  std::string GetSubsystem(const Sendable* sendable) const;
-
-  /**
-   * Sets the subsystem name of an object.
-   *
-   * @param sendable object
-   * @param subsystem subsystem name
-   */
-  void SetSubsystem(Sendable* sendable, const wpi::Twine& subsystem);
-
-  /**
-   * Gets a unique handle for setting/getting data with SetData() and GetData().
-   *
-   * @return Handle
-   */
-  int GetDataHandle();
-
-  /**
-   * 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)
-   */
-  std::shared_ptr<void> SetData(Sendable* sendable, int handle,
-                                std::shared_ptr<void> data);
-
-  /**
-   * 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)
-   */
-  std::shared_ptr<void> GetData(Sendable* sendable, int handle);
-
-  /**
-   * Enables LiveWindow for an object.
-   *
-   * @param sendable object
-   */
-  void EnableLiveWindow(Sendable* sendable);
-
-  /**
-   * Disables LiveWindow for an object.
-   *
-   * @param sendable object
-   */
-  void DisableLiveWindow(Sendable* sendable);
-
-  /**
-   * Get unique id for an object.  Since objects can move, use this instead
-   * of storing Sendable* directly if ownership is in question.
-   *
-   * @param sendable object
-   * @return unique id
-   */
-  UID GetUniqueId(Sendable* sendable);
-
-  /**
-   * Get sendable object for a given unique id.
-   *
-   * @param uid unique id
-   * @return sendable object (may be null)
-   */
-  Sendable* GetSendable(UID uid);
-
-  /**
-   * Publishes an object in the registry to a network table.
-   *
-   * @param sendableUid sendable unique id
-   * @param table network table
-   */
-  void Publish(UID sendableUid, std::shared_ptr<NetworkTable> table);
-
-  /**
-   * Updates network table information from an object.
-   *
-   * @param sendableUid sendable unique id
-   */
-  void Update(UID sendableUid);
-
-  /**
-   * Data passed to ForeachLiveWindow() callback function
-   */
-  struct CallbackData {
-    CallbackData(Sendable* sendable_, wpi::StringRef name_,
-                 wpi::StringRef subsystem_, Sendable* parent_,
-                 std::shared_ptr<void>& data_, SendableBuilderImpl& builder_)
-        : sendable(sendable_),
-          name(name_),
-          subsystem(subsystem_),
-          parent(parent_),
-          data(data_),
-          builder(builder_) {}
-
-    Sendable* sendable;
-    wpi::StringRef name;
-    wpi::StringRef subsystem;
-    Sendable* parent;
-    std::shared_ptr<void>& data;
-    SendableBuilderImpl& builder;
-  };
-
-  /**
-   * Iterates over LiveWindow-enabled objects in the registry.
-   * It is *not* safe to call other SendableRegistry functions from the
-   * callback (this will likely deadlock).
-   *
-   * @param dataHandle data handle to get data pointer passed to callback
-   * @param callback function to call for each object
-   */
-  void ForeachLiveWindow(
-      int dataHandle,
-      wpi::function_ref<void(CallbackData& cbdata)> callback) const;
-
- private:
-  SendableRegistry();
-
-  struct Impl;
-  std::unique_ptr<Impl> m_impl;
-};
-
-}  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/smartdashboard/SmartDashboard.h b/wpilibc/src/main/native/include/frc/smartdashboard/SmartDashboard.h
index 9fdc049..47c4a28 100644
--- a/wpilibc/src/main/native/include/frc/smartdashboard/SmartDashboard.h
+++ b/wpilibc/src/main/native/include/frc/smartdashboard/SmartDashboard.h
@@ -1,30 +1,28 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2011-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.
 
 #pragma once
 
 #include <memory>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include <networktables/NetworkTableEntry.h>
 #include <networktables/NetworkTableValue.h>
+#include <wpi/span.h>
 
-#include "frc/ErrorBase.h"
-#include "frc/smartdashboard/ListenerExecutor.h"
-#include "frc/smartdashboard/Sendable.h"
-#include "frc/smartdashboard/SendableHelper.h"
+namespace wpi {
+class Sendable;
+}  // namespace wpi
 
 namespace frc {
 
-class SmartDashboard : public ErrorBase,
-                       public Sendable,
-                       public SendableHelper<SmartDashboard> {
+class SmartDashboard {
  public:
+  SmartDashboard() = delete;
+
   static void init();
 
   /**
@@ -33,7 +31,7 @@
    * @param key the key to search for
    * @return true if the table as a value assigned to the given key
    */
-  static bool ContainsKey(wpi::StringRef key);
+  static bool ContainsKey(std::string_view key);
 
   /**
    * @param types bitmask of types; 0 is treated as a "don't care".
@@ -46,7 +44,7 @@
    *
    * @param key the key to make persistent
    */
-  static void SetPersistent(wpi::StringRef key);
+  static void SetPersistent(std::string_view key);
 
   /**
    * Stop making a key's value persistent through program restarts.
@@ -54,7 +52,7 @@
    *
    * @param key the key name
    */
-  static void ClearPersistent(wpi::StringRef key);
+  static void ClearPersistent(std::string_view key);
 
   /**
    * Returns whether the value is persistent through program restarts.
@@ -62,7 +60,7 @@
    *
    * @param key the key name
    */
-  static bool IsPersistent(wpi::StringRef key);
+  static bool IsPersistent(std::string_view key);
 
   /**
    * Sets flags on the specified key in this table. The key can
@@ -71,7 +69,7 @@
    * @param key the key name
    * @param flags the flags to set (bitmask)
    */
-  static void SetFlags(wpi::StringRef key, unsigned int flags);
+  static void SetFlags(std::string_view key, unsigned int flags);
 
   /**
    * Clears flags on the specified key in this table. The key can
@@ -80,7 +78,7 @@
    * @param key the key name
    * @param flags the flags to clear (bitmask)
    */
-  static void ClearFlags(wpi::StringRef key, unsigned int flags);
+  static void ClearFlags(std::string_view key, unsigned int flags);
 
   /**
    * Returns the flags for the specified key.
@@ -88,14 +86,14 @@
    * @param key the key name
    * @return the flags, or 0 if the key is not defined
    */
-  static unsigned int GetFlags(wpi::StringRef key);
+  static unsigned int GetFlags(std::string_view key);
 
   /**
    * Deletes the specified key in this table.
    *
    * @param key the key name
    */
-  static void Delete(wpi::StringRef key);
+  static void Delete(std::string_view key);
 
   /**
    * Returns an NT Entry mapping to the specified key
@@ -105,7 +103,7 @@
    * @param key the key
    * @return    the entry for the key
    */
-  static nt::NetworkTableEntry GetEntry(wpi::StringRef key);
+  static nt::NetworkTableEntry GetEntry(std::string_view key);
 
   /**
    * Maps the specified key to the specified value in this table.
@@ -116,10 +114,10 @@
    * In order for the value to appear in the dashboard, it must be registered
    * with SendableRegistry.  WPILib components do this automatically.
    *
-   * @param keyName the key
-   * @param value   the value
+   * @param key  the key
+   * @param data the value
    */
-  static void PutData(wpi::StringRef key, Sendable* data);
+  static void PutData(std::string_view key, wpi::Sendable* data);
 
   /**
    * Maps the specified key (where the key is the name of the Sendable)
@@ -133,7 +131,7 @@
    *
    * @param value the value
    */
-  static void PutData(Sendable* value);
+  static void PutData(wpi::Sendable* value);
 
   /**
    * Returns the value at the specified key.
@@ -141,7 +139,7 @@
    * @param keyName the key
    * @return the value
    */
-  static Sendable* GetData(wpi::StringRef keyName);
+  static wpi::Sendable* GetData(std::string_view keyName);
 
   /**
    * Maps the specified key to the specified value in this table.
@@ -153,7 +151,7 @@
    * @param value   the value
    * @return        False if the table key already exists with a different type
    */
-  static bool PutBoolean(wpi::StringRef keyName, bool value);
+  static bool PutBoolean(std::string_view keyName, bool value);
 
   /**
    * Gets the current value in the table, setting it if it does not exist.
@@ -161,7 +159,7 @@
    * @param defaultValue the default value to set if key doesn't exist.
    * @returns False if the table key exists with a different type
    */
-  static bool SetDefaultBoolean(wpi::StringRef key, bool defaultValue);
+  static bool SetDefaultBoolean(std::string_view key, bool defaultValue);
 
   /**
    * Returns the value at the specified key.
@@ -169,9 +167,10 @@
    * If the key is not found, returns the default value.
    *
    * @param keyName the key
+   * @param defaultValue the default value to set if key doesn't exist
    * @return the value
    */
-  static bool GetBoolean(wpi::StringRef keyName, bool defaultValue);
+  static bool GetBoolean(std::string_view keyName, bool defaultValue);
 
   /**
    * Maps the specified key to the specified value in this table.
@@ -183,7 +182,7 @@
    * @param value   the value
    * @return        False if the table key already exists with a different type
    */
-  static bool PutNumber(wpi::StringRef keyName, double value);
+  static bool PutNumber(std::string_view keyName, double value);
 
   /**
    * Gets the current value in the table, setting it if it does not exist.
@@ -192,7 +191,7 @@
    * @param defaultValue The default value to set if key doesn't exist.
    * @returns False if the table key exists with a different type
    */
-  static bool SetDefaultNumber(wpi::StringRef key, double defaultValue);
+  static bool SetDefaultNumber(std::string_view key, double defaultValue);
 
   /**
    * Returns the value at the specified key.
@@ -200,9 +199,10 @@
    * If the key is not found, returns the default value.
    *
    * @param keyName the key
+   * @param defaultValue the default value to set if the key doesn't exist
    * @return the value
    */
-  static double GetNumber(wpi::StringRef keyName, double defaultValue);
+  static double GetNumber(std::string_view keyName, double defaultValue);
 
   /**
    * Maps the specified key to the specified value in this table.
@@ -214,7 +214,7 @@
    * @param value   the value
    * @return        False if the table key already exists with a different type
    */
-  static bool PutString(wpi::StringRef keyName, wpi::StringRef value);
+  static bool PutString(std::string_view keyName, std::string_view value);
 
   /**
    * Gets the current value in the table, setting it if it does not exist.
@@ -223,7 +223,8 @@
    * @param defaultValue the default value to set if key doesn't exist.
    * @returns False if the table key exists with a different type
    */
-  static bool SetDefaultString(wpi::StringRef key, wpi::StringRef defaultValue);
+  static bool SetDefaultString(std::string_view key,
+                               std::string_view defaultValue);
 
   /**
    * Returns the value at the specified key.
@@ -231,10 +232,11 @@
    * If the key is not found, returns the default value.
    *
    * @param keyName the key
+   * @param defaultValue the default value to set if the key doesn't exist
    * @return the value
    */
-  static std::string GetString(wpi::StringRef keyName,
-                               wpi::StringRef defaultValue);
+  static std::string GetString(std::string_view keyName,
+                               std::string_view defaultValue);
 
   /**
    * Put a boolean array in the table.
@@ -247,7 +249,7 @@
    *       std::vector<bool> is special-cased in C++. 0 is false, any
    *       non-zero value is true.
    */
-  static bool PutBooleanArray(wpi::StringRef key, wpi::ArrayRef<int> value);
+  static bool PutBooleanArray(std::string_view key, wpi::span<const int> value);
 
   /**
    * Gets the current value in the table, setting it if it does not exist.
@@ -256,8 +258,8 @@
    * @param defaultValue the default value to set if key doesn't exist.
    * @returns False if the table key exists with a different type
    */
-  static bool SetDefaultBooleanArray(wpi::StringRef key,
-                                     wpi::ArrayRef<int> defaultValue);
+  static bool SetDefaultBooleanArray(std::string_view key,
+                                     wpi::span<const int> defaultValue);
 
   /**
    * Returns the boolean array the key maps to.
@@ -277,8 +279,8 @@
    *       because std::vector<bool> is special-cased in C++. 0 is false, any
    *       non-zero value is true.
    */
-  static std::vector<int> GetBooleanArray(wpi::StringRef key,
-                                          wpi::ArrayRef<int> defaultValue);
+  static std::vector<int> GetBooleanArray(std::string_view key,
+                                          wpi::span<const int> defaultValue);
 
   /**
    * Put a number array in the table.
@@ -287,7 +289,8 @@
    * @param value The value that will be assigned.
    * @return False if the table key already exists with a different type
    */
-  static bool PutNumberArray(wpi::StringRef key, wpi::ArrayRef<double> value);
+  static bool PutNumberArray(std::string_view key,
+                             wpi::span<const double> value);
 
   /**
    * Gets the current value in the table, setting it if it does not exist.
@@ -296,8 +299,8 @@
    * @param defaultValue The default value to set if key doesn't exist.
    * @returns False if the table key exists with a different type
    */
-  static bool SetDefaultNumberArray(wpi::StringRef key,
-                                    wpi::ArrayRef<double> defaultValue);
+  static bool SetDefaultNumberArray(std::string_view key,
+                                    wpi::span<const double> defaultValue);
 
   /**
    * Returns the number array the key maps to.
@@ -313,8 +316,8 @@
    * @note This makes a copy of the array. If the overhead of this is a concern,
    *       use GetValue() instead.
    */
-  static std::vector<double> GetNumberArray(wpi::StringRef key,
-                                            wpi::ArrayRef<double> defaultValue);
+  static std::vector<double> GetNumberArray(
+      std::string_view key, wpi::span<const double> defaultValue);
 
   /**
    * Put a string array in the table.
@@ -323,8 +326,8 @@
    * @param value The value that will be assigned.
    * @return False if the table key already exists with a different type
    */
-  static bool PutStringArray(wpi::StringRef key,
-                             wpi::ArrayRef<std::string> value);
+  static bool PutStringArray(std::string_view key,
+                             wpi::span<const std::string> value);
 
   /**
    * Gets the current value in the table, setting it if it does not exist.
@@ -333,8 +336,8 @@
    * @param defaultValue The default value to set if key doesn't exist.
    * @returns False if the table key exists with a different type
    */
-  static bool SetDefaultStringArray(wpi::StringRef key,
-                                    wpi::ArrayRef<std::string> defaultValue);
+  static bool SetDefaultStringArray(std::string_view key,
+                                    wpi::span<const std::string> defaultValue);
 
   /**
    * Returns the string array the key maps to.
@@ -351,7 +354,7 @@
    *       use GetValue() instead.
    */
   static std::vector<std::string> GetStringArray(
-      wpi::StringRef key, wpi::ArrayRef<std::string> defaultValue);
+      std::string_view key, wpi::span<const std::string> defaultValue);
 
   /**
    * Put a raw value (byte array) in the table.
@@ -360,7 +363,7 @@
    * @param value The value that will be assigned.
    * @return False if the table key already exists with a different type
    */
-  static bool PutRaw(wpi::StringRef key, wpi::StringRef value);
+  static bool PutRaw(std::string_view key, std::string_view value);
 
   /**
    * Gets the current value in the table, setting it if it does not exist.
@@ -369,7 +372,8 @@
    * @param defaultValue The default value to set if key doesn't exist.
    * @returns False if the table key exists with a different type
    */
-  static bool SetDefaultRaw(wpi::StringRef key, wpi::StringRef defaultValue);
+  static bool SetDefaultRaw(std::string_view key,
+                            std::string_view defaultValue);
 
   /**
    * Returns the raw value (byte array) the key maps to.
@@ -385,7 +389,8 @@
    * @note This makes a copy of the raw contents. If the overhead of this is a
    *       concern, use GetValue() instead.
    */
-  static std::string GetRaw(wpi::StringRef key, wpi::StringRef defaultValue);
+  static std::string GetRaw(std::string_view key,
+                            std::string_view defaultValue);
 
   /**
    * Maps the specified key to the specified complex value (such as an array) in
@@ -398,7 +403,7 @@
    * @param value   the value
    * @return        False if the table key already exists with a different type
    */
-  static bool PutValue(wpi::StringRef keyName,
+  static bool PutValue(std::string_view keyName,
                        std::shared_ptr<nt::Value> value);
 
   /**
@@ -408,7 +413,7 @@
    * @param defaultValue The default value to set if key doesn't exist.
    * @returns False if the table key exists with a different type
    */
-  static bool SetDefaultValue(wpi::StringRef key,
+  static bool SetDefaultValue(std::string_view key,
                               std::shared_ptr<nt::Value> defaultValue);
 
   /**
@@ -416,14 +421,12 @@
    * complex data object.
    *
    * @param keyName the key
-   * @param value   the object to retrieve the value into
    */
-  static std::shared_ptr<nt::Value> GetValue(wpi::StringRef keyName);
+  static std::shared_ptr<nt::Value> GetValue(std::string_view keyName);
 
   /**
    * 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()}.
+   * synchronously from the main loop on the next call to updateValues().
    *
    * @param task The task to run synchronously from the main thread.
    */
@@ -433,11 +436,6 @@
    * Puts all sendable data to the dashboard.
    */
   static void UpdateValues();
-
- private:
-  virtual ~SmartDashboard() = default;
-
-  static detail::ListenerExecutor listenerExecutor;
 };
 
 }  // namespace frc
diff --git a/wpilibc/src/main/native/include/frc/util/Color.h b/wpilibc/src/main/native/include/frc/util/Color.h
index 1321380..00bc4af 100644
--- a/wpilibc/src/main/native/include/frc/util/Color.h
+++ b/wpilibc/src/main/native/include/frc/util/Color.h
@@ -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.
 
 #pragma once
 
@@ -23,17 +20,17 @@
    */
 
   /**
-   * #1560BD.
+   * 0x1560BD.
    */
   static const Color kDenim;
 
   /**
-   * #0066B3.
+   * 0x0066B3.
    */
   static const Color kFirstBlue;
 
   /**
-   * #ED1C24.
+   * 0xED1C24.
    */
   static const Color kFirstRed;
 
@@ -42,702 +39,702 @@
    */
 
   /**
-   * #F0F8FF.
+   * 0xF0F8FF.
    */
   static const Color kAliceBlue;
 
   /**
-   * #FAEBD7.
+   * 0xFAEBD7.
    */
   static const Color kAntiqueWhite;
 
   /**
-   * #00FFFF.
+   * 0x00FFFF.
    */
   static const Color kAqua;
 
   /**
-   * #7FFFD4.
+   * 0x7FFFD4.
    */
   static const Color kAquamarine;
 
   /**
-   * #F0FFFF.
+   * 0xF0FFFF.
    */
   static const Color kAzure;
 
   /**
-   * #F5F5DC.
+   * 0xF5F5DC.
    */
   static const Color kBeige;
 
   /**
-   * #FFE4C4.
+   * 0xFFE4C4.
    */
   static const Color kBisque;
 
   /**
-   * #000000.
+   * 0x000000.
    */
   static const Color kBlack;
 
   /**
-   * #FFEBCD.
+   * 0xFFEBCD.
    */
   static const Color kBlanchedAlmond;
 
   /**
-   * #0000FF.
+   * 0x0000FF.
    */
   static const Color kBlue;
 
   /**
-   * #8A2BE2.
+   * 0x8A2BE2.
    */
   static const Color kBlueViolet;
 
   /**
-   * #A52A2A.
+   * 0xA52A2A.
    */
   static const Color kBrown;
 
   /**
-   * #DEB887.
+   * 0xDEB887.
    */
   static const Color kBurlywood;
 
   /**
-   * #5F9EA0.
+   * 0x5F9EA0.
    */
   static const Color kCadetBlue;
 
   /**
-   * #7FFF00.
+   * 0x7FFF00.
    */
   static const Color kChartreuse;
 
   /**
-   * #D2691E.
+   * 0xD2691E.
    */
   static const Color kChocolate;
 
   /**
-   * #FF7F50.
+   * 0xFF7F50.
    */
   static const Color kCoral;
 
   /**
-   * #6495ED.
+   * 0x6495ED.
    */
   static const Color kCornflowerBlue;
 
   /**
-   * #FFF8DC.
+   * 0xFFF8DC.
    */
   static const Color kCornsilk;
 
   /**
-   * #DC143C.
+   * 0xDC143C.
    */
   static const Color kCrimson;
 
   /**
-   * #00FFFF.
+   * 0x00FFFF.
    */
   static const Color kCyan;
 
   /**
-   * #00008B.
+   * 0x00008B.
    */
   static const Color kDarkBlue;
 
   /**
-   * #008B8B.
+   * 0x008B8B.
    */
   static const Color kDarkCyan;
 
   /**
-   * #B8860B.
+   * 0xB8860B.
    */
   static const Color kDarkGoldenrod;
 
   /**
-   * #A9A9A9.
+   * 0xA9A9A9.
    */
   static const Color kDarkGray;
 
   /**
-   * #006400.
+   * 0x006400.
    */
   static const Color kDarkGreen;
 
   /**
-   * #BDB76B.
+   * 0xBDB76B.
    */
   static const Color kDarkKhaki;
 
   /**
-   * #8B008B.
+   * 0x8B008B.
    */
   static const Color kDarkMagenta;
 
   /**
-   * #556B2F.
+   * 0x556B2F.
    */
   static const Color kDarkOliveGreen;
 
   /**
-   * #FF8C00.
+   * 0xFF8C00.
    */
   static const Color kDarkOrange;
 
   /**
-   * #9932CC.
+   * 0x9932CC.
    */
   static const Color kDarkOrchid;
 
   /**
-   * #8B0000.
+   * 0x8B0000.
    */
   static const Color kDarkRed;
 
   /**
-   * #E9967A.
+   * 0xE9967A.
    */
   static const Color kDarkSalmon;
 
   /**
-   * #8FBC8F.
+   * 0x8FBC8F.
    */
   static const Color kDarkSeaGreen;
 
   /**
-   * #483D8B.
+   * 0x483D8B.
    */
   static const Color kDarkSlateBlue;
 
   /**
-   * #2F4F4F.
+   * 0x2F4F4F.
    */
   static const Color kDarkSlateGray;
 
   /**
-   * #00CED1.
+   * 0x00CED1.
    */
   static const Color kDarkTurquoise;
 
   /**
-   * #9400D3.
+   * 0x9400D3.
    */
   static const Color kDarkViolet;
 
   /**
-   * #FF1493.
+   * 0xFF1493.
    */
   static const Color kDeepPink;
 
   /**
-   * #00BFFF.
+   * 0x00BFFF.
    */
   static const Color kDeepSkyBlue;
 
   /**
-   * #696969.
+   * 0x696969.
    */
   static const Color kDimGray;
 
   /**
-   * #1E90FF.
+   * 0x1E90FF.
    */
   static const Color kDodgerBlue;
 
   /**
-   * #B22222.
+   * 0xB22222.
    */
   static const Color kFirebrick;
 
   /**
-   * #FFFAF0.
+   * 0xFFFAF0.
    */
   static const Color kFloralWhite;
 
   /**
-   * #228B22.
+   * 0x228B22.
    */
   static const Color kForestGreen;
 
   /**
-   * #FF00FF.
+   * 0xFF00FF.
    */
   static const Color kFuchsia;
 
   /**
-   * #DCDCDC.
+   * 0xDCDCDC.
    */
   static const Color kGainsboro;
 
   /**
-   * #F8F8FF.
+   * 0xF8F8FF.
    */
   static const Color kGhostWhite;
 
   /**
-   * #FFD700.
+   * 0xFFD700.
    */
   static const Color kGold;
 
   /**
-   * #DAA520.
+   * 0xDAA520.
    */
   static const Color kGoldenrod;
 
   /**
-   * #808080.
+   * 0x808080.
    */
   static const Color kGray;
 
   /**
-   * #008000.
+   * 0x008000.
    */
   static const Color kGreen;
 
   /**
-   * #ADFF2F.
+   * 0xADFF2F.
    */
   static const Color kGreenYellow;
 
   /**
-   * #F0FFF0.
+   * 0xF0FFF0.
    */
   static const Color kHoneydew;
 
   /**
-   * #FF69B4.
+   * 0xFF69B4.
    */
   static const Color kHotPink;
 
   /**
-   * #CD5C5C.
+   * 0xCD5C5C.
    */
   static const Color kIndianRed;
 
   /**
-   * #4B0082.
+   * 0x4B0082.
    */
   static const Color kIndigo;
 
   /**
-   * #FFFFF0.
+   * 0xFFFFF0.
    */
   static const Color kIvory;
 
   /**
-   * #F0E68C.
+   * 0xF0E68C.
    */
   static const Color kKhaki;
 
   /**
-   * #E6E6FA.
+   * 0xE6E6FA.
    */
   static const Color kLavender;
 
   /**
-   * #FFF0F5.
+   * 0xFFF0F5.
    */
   static const Color kLavenderBlush;
 
   /**
-   * #7CFC00.
+   * 0x7CFC00.
    */
   static const Color kLawnGreen;
 
   /**
-   * #FFFACD.
+   * 0xFFFACD.
    */
   static const Color kLemonChiffon;
 
   /**
-   * #ADD8E6.
+   * 0xADD8E6.
    */
   static const Color kLightBlue;
 
   /**
-   * #F08080.
+   * 0xF08080.
    */
   static const Color kLightCoral;
 
   /**
-   * #E0FFFF.
+   * 0xE0FFFF.
    */
   static const Color kLightCyan;
 
   /**
-   * #FAFAD2.
+   * 0xFAFAD2.
    */
   static const Color kLightGoldenrodYellow;
 
   /**
-   * #D3D3D3.
+   * 0xD3D3D3.
    */
   static const Color kLightGray;
 
   /**
-   * #90EE90.
+   * 0x90EE90.
    */
   static const Color kLightGreen;
 
   /**
-   * #FFB6C1.
+   * 0xFFB6C1.
    */
   static const Color kLightPink;
 
   /**
-   * #FFA07A.
+   * 0xFFA07A.
    */
   static const Color kLightSalmon;
 
   /**
-   * #20B2AA.
+   * 0x20B2AA.
    */
   static const Color kLightSeaGreen;
 
   /**
-   * #87CEFA.
+   * 0x87CEFA.
    */
   static const Color kLightSkyBlue;
 
   /**
-   * #778899.
+   * 0x778899.
    */
   static const Color kLightSlateGray;
 
   /**
-   * #B0C4DE.
+   * 0xB0C4DE.
    */
   static const Color kLightSteelBlue;
 
   /**
-   * #FFFFE0.
+   * 0xFFFFE0.
    */
   static const Color kLightYellow;
 
   /**
-   * #00FF00.
+   * 0x00FF00.
    */
   static const Color kLime;
 
   /**
-   * #32CD32.
+   * 0x32CD32.
    */
   static const Color kLimeGreen;
 
   /**
-   * #FAF0E6.
+   * 0xFAF0E6.
    */
   static const Color kLinen;
 
   /**
-   * #FF00FF.
+   * 0xFF00FF.
    */
   static const Color kMagenta;
 
   /**
-   * #800000.
+   * 0x800000.
    */
   static const Color kMaroon;
 
   /**
-   * #66CDAA.
+   * 0x66CDAA.
    */
   static const Color kMediumAquamarine;
 
   /**
-   * #0000CD.
+   * 0x0000CD.
    */
   static const Color kMediumBlue;
 
   /**
-   * #BA55D3.
+   * 0xBA55D3.
    */
   static const Color kMediumOrchid;
 
   /**
-   * #9370DB.
+   * 0x9370DB.
    */
   static const Color kMediumPurple;
 
   /**
-   * #3CB371.
+   * 0x3CB371.
    */
   static const Color kMediumSeaGreen;
 
   /**
-   * #7B68EE.
+   * 0x7B68EE.
    */
   static const Color kMediumSlateBlue;
 
   /**
-   * #00FA9A.
+   * 0x00FA9A.
    */
   static const Color kMediumSpringGreen;
 
   /**
-   * #48D1CC.
+   * 0x48D1CC.
    */
   static const Color kMediumTurquoise;
 
   /**
-   * #C71585.
+   * 0xC71585.
    */
   static const Color kMediumVioletRed;
 
   /**
-   * #191970.
+   * 0x191970.
    */
   static const Color kMidnightBlue;
 
   /**
-   * #F5FFFA.
+   * 0xF5FFFA.
    */
   static const Color kMintcream;
 
   /**
-   * #FFE4E1.
+   * 0xFFE4E1.
    */
   static const Color kMistyRose;
 
   /**
-   * #FFE4B5.
+   * 0xFFE4B5.
    */
   static const Color kMoccasin;
 
   /**
-   * #FFDEAD.
+   * 0xFFDEAD.
    */
   static const Color kNavajoWhite;
 
   /**
-   * #000080.
+   * 0x000080.
    */
   static const Color kNavy;
 
   /**
-   * #FDF5E6.
+   * 0xFDF5E6.
    */
   static const Color kOldLace;
 
   /**
-   * #808000.
+   * 0x808000.
    */
   static const Color kOlive;
 
   /**
-   * #6B8E23.
+   * 0x6B8E23.
    */
   static const Color kOliveDrab;
 
   /**
-   * #FFA500.
+   * 0xFFA500.
    */
   static const Color kOrange;
 
   /**
-   * #FF4500.
+   * 0xFF4500.
    */
   static const Color kOrangeRed;
 
   /**
-   * #DA70D6.
+   * 0xDA70D6.
    */
   static const Color kOrchid;
 
   /**
-   * #EEE8AA.
+   * 0xEEE8AA.
    */
   static const Color kPaleGoldenrod;
 
   /**
-   * #98FB98.
+   * 0x98FB98.
    */
   static const Color kPaleGreen;
 
   /**
-   * #AFEEEE.
+   * 0xAFEEEE.
    */
   static const Color kPaleTurquoise;
 
   /**
-   * #DB7093.
+   * 0xDB7093.
    */
   static const Color kPaleVioletRed;
 
   /**
-   * #FFEFD5.
+   * 0xFFEFD5.
    */
   static const Color kPapayaWhip;
 
   /**
-   * #FFDAB9.
+   * 0xFFDAB9.
    */
   static const Color kPeachPuff;
 
   /**
-   * #CD853F.
+   * 0xCD853F.
    */
   static const Color kPeru;
 
   /**
-   * #FFC0CB.
+   * 0xFFC0CB.
    */
   static const Color kPink;
 
   /**
-   * #DDA0DD.
+   * 0xDDA0DD.
    */
   static const Color kPlum;
 
   /**
-   * #B0E0E6.
+   * 0xB0E0E6.
    */
   static const Color kPowderBlue;
 
   /**
-   * #800080.
+   * 0x800080.
    */
   static const Color kPurple;
 
   /**
-   * #FF0000.
+   * 0xFF0000.
    */
   static const Color kRed;
 
   /**
-   * #BC8F8F.
+   * 0xBC8F8F.
    */
   static const Color kRosyBrown;
 
   /**
-   * #4169E1.
+   * 0x4169E1.
    */
   static const Color kRoyalBlue;
 
   /**
-   * #8B4513.
+   * 0x8B4513.
    */
   static const Color kSaddleBrown;
 
   /**
-   * #FA8072.
+   * 0xFA8072.
    */
   static const Color kSalmon;
 
   /**
-   * #F4A460.
+   * 0xF4A460.
    */
   static const Color kSandyBrown;
 
   /**
-   * #2E8B57.
+   * 0x2E8B57.
    */
   static const Color kSeaGreen;
 
   /**
-   * #FFF5EE.
+   * 0xFFF5EE.
    */
   static const Color kSeashell;
 
   /**
-   * #A0522D.
+   * 0xA0522D.
    */
   static const Color kSienna;
 
   /**
-   * #C0C0C0.
+   * 0xC0C0C0.
    */
   static const Color kSilver;
 
   /**
-   * #87CEEB.
+   * 0x87CEEB.
    */
   static const Color kSkyBlue;
 
   /**
-   * #6A5ACD.
+   * 0x6A5ACD.
    */
   static const Color kSlateBlue;
 
   /**
-   * #708090.
+   * 0x708090.
    */
   static const Color kSlateGray;
 
   /**
-   * #FFFAFA.
+   * 0xFFFAFA.
    */
   static const Color kSnow;
 
   /**
-   * #00FF7F.
+   * 0x00FF7F.
    */
   static const Color kSpringGreen;
 
   /**
-   * #4682B4.
+   * 0x4682B4.
    */
   static const Color kSteelBlue;
 
   /**
-   * #D2B48C.
+   * 0xD2B48C.
    */
   static const Color kTan;
 
   /**
-   * #008080.
+   * 0x008080.
    */
   static const Color kTeal;
 
   /**
-   * #D8BFD8.
+   * 0xD8BFD8.
    */
   static const Color kThistle;
 
   /**
-   * #FF6347.
+   * 0xFF6347.
    */
   static const Color kTomato;
 
   /**
-   * #40E0D0.
+   * 0x40E0D0.
    */
   static const Color kTurquoise;
 
   /**
-   * #EE82EE.
+   * 0xEE82EE.
    */
   static const Color kViolet;
 
   /**
-   * #F5DEB3.
+   * 0xF5DEB3.
    */
   static const Color kWheat;
 
   /**
-   * #FFFFFF.
+   * 0xFFFFFF.
    */
   static const Color kWhite;
 
   /**
-   * #F5F5F5.
+   * 0xF5F5F5.
    */
   static const Color kWhiteSmoke;
 
   /**
-   * #FFFF00.
+   * 0xFFFF00.
    */
   static const Color kYellow;
 
   /**
-   * #9ACD32.
+   * 0x9ACD32.
    */
   static const Color kYellowGreen;
 
@@ -746,9 +743,9 @@
   /**
    * Constructs a Color.
    *
-   * @param red Red value (0-1)
-   * @param green Green value (0-1)
-   * @param blue Blue value (0-1)
+   * @param r Red value (0-1)
+   * @param g Green value (0-1)
+   * @param b Blue value (0-1)
    */
   constexpr Color(double r, double g, double b)
       : red(roundAndClamp(r)),
@@ -809,6 +806,10 @@
   return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue;
 }
 
+inline bool operator!=(const Color& c1, const Color& c2) {
+  return !(c1 == c2);
+}
+
 /*
  * FIRST Colors
  */
diff --git a/wpilibc/src/main/native/include/frc/util/Color8Bit.h b/wpilibc/src/main/native/include/frc/util/Color8Bit.h
index d5dba07..62cbde9 100644
--- a/wpilibc/src/main/native/include/frc/util/Color8Bit.h
+++ b/wpilibc/src/main/native/include/frc/util/Color8Bit.h
@@ -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.
 
 #pragma once
 
@@ -23,9 +20,9 @@
   /**
    * Constructs a Color8Bit.
    *
-   * @param red Red value (0-255)
-   * @param green Green value (0-255)
-   * @param blue Blue value (0-255)
+   * @param r Red value (0-255)
+   * @param g Green value (0-255)
+   * @param b Blue value (0-255)
    */
   constexpr Color8Bit(int r, int g, int b)
       : red(std::clamp(r, 0, 255)),
@@ -37,12 +34,12 @@
    *
    * @param color The color
    */
-  constexpr Color8Bit(const Color& color)
+  constexpr Color8Bit(const Color& color)  // NOLINT
       : red(color.red * 255),
         green(color.green * 255),
         blue(color.blue * 255) {}
 
-  constexpr operator Color() const {
+  constexpr operator Color() const {  // NOLINT
     return Color(red / 255.0, green / 255.0, blue / 255.0);
   }
 
diff --git a/wpilibc/src/main/native/include/frc2/Timer.h b/wpilibc/src/main/native/include/frc2/Timer.h
deleted file mode 100644
index 8f943a6..0000000
--- a/wpilibc/src/main/native/include/frc2/Timer.h
+++ /dev/null
@@ -1,151 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <units/time.h>
-#include <wpi/mutex.h>
-
-namespace frc2 {
-
-/**
- * Pause the task for a specified time.
- *
- * Pause the execution of the program for a specified period of time given in
- * seconds. Motors will continue to run at their last assigned values, and
- * sensors will continue to update. Only the task containing the wait will pause
- * until the wait time is expired.
- *
- * @param seconds Length of time to pause, in seconds.
- */
-void Wait(units::second_t seconds);
-
-/**
- * @brief  Gives real-time clock system time with nanosecond resolution
- * @return The time, just in case you want the robot to start autonomous at 8pm
- *         on Saturday.
- */
-units::second_t GetTime();
-
-/**
- * A wrapper for the frc::Timer class that returns unit-typed values.
- */
-class Timer {
- public:
-  /**
-   * Create a new timer object.
-   *
-   * Create a new timer object and reset the time to zero. The timer is
-   * initially not running and must be started.
-   */
-  Timer();
-
-  virtual ~Timer() = default;
-
-  Timer(const Timer& rhs);
-  Timer& operator=(const Timer& rhs);
-  Timer(Timer&& rhs);
-  Timer& operator=(Timer&& rhs);
-
-  /**
-   * Get the current time from the timer. If the clock is running it is derived
-   * from the current system clock the start time stored in the timer class. If
-   * the clock is not running, then return the time when it was last stopped.
-   *
-   * @return Current time value for this timer in seconds
-   */
-  units::second_t Get() const;
-
-  /**
-   * Reset the timer by setting the time to 0.
-   *
-   * Make the timer startTime the current time so new requests will be relative
-   * to now.
-   */
-  void Reset();
-
-  /**
-   * Start the timer running.
-   *
-   * Just set the running flag to true indicating that all time requests should
-   * be relative to the system clock. Note that this method is a no-op if the
-   * timer is already running.
-   */
-  void Start();
-
-  /**
-   * Stop the timer.
-   *
-   * This computes the time as of now and clears the running flag, causing all
-   * subsequent time requests to be read from the accumulated time rather than
-   * looking at the system clock.
-   */
-  void Stop();
-
-  /**
-   * Check if the period specified has passed.
-   *
-   * @param seconds The period to check.
-   * @return        True if the period has passed.
-   */
-  bool HasElapsed(units::second_t period) const;
-
-  /**
-   * Check if the period specified has passed and if it has, advance the start
-   * time by that period. This is useful to decide if it's time to do periodic
-   * work without drifting later by the time it took to get around to checking.
-   *
-   * @param period The period to check for.
-   * @return       True if the period has passed.
-   */
-  bool HasPeriodPassed(units::second_t period);
-
-  /**
-   * Check if the period specified has passed and if it has, advance the start
-   * time by that period. This is useful to decide if it's time to do periodic
-   * work without drifting later by the time it took to get around to checking.
-   *
-   * @param period The period to check for.
-   * @return       True if the period has passed.
-   */
-  bool AdvanceIfElapsed(units::second_t period);
-
-  /**
-   * Return the FPGA system clock time in seconds.
-   *
-   * Return the time from the FPGA hardware clock in seconds since the FPGA
-   * started. Rolls over after 71 minutes.
-   *
-   * @returns Robot running time in seconds.
-   */
-  static units::second_t GetFPGATimestamp();
-
-  /**
-   * 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.
-   *
-   * @return Time remaining in current match period (auto or teleop)
-   */
-  static units::second_t GetMatchTime();
-
- private:
-  units::second_t m_startTime = 0_s;
-  units::second_t m_accumulatedTime = 0_s;
-  bool m_running = false;
-  mutable wpi::mutex m_mutex;
-};
-
-}  // namespace frc2