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/hal/src/main/native/sim/Accelerometer.cpp b/hal/src/main/native/sim/Accelerometer.cpp
index 1435fd5..2756c99 100644
--- a/hal/src/main/native/sim/Accelerometer.cpp
+++ b/hal/src/main/native/sim/Accelerometer.cpp
@@ -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.
 
 #include "hal/Accelerometer.h"
 
@@ -11,11 +8,9 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAccelerometer() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 void HAL_SetAccelerometerActive(HAL_Bool active) {
@@ -25,7 +20,13 @@
 void HAL_SetAccelerometerRange(HAL_AccelerometerRange range) {
   SimAccelerometerData[0].range = range;
 }
-double HAL_GetAccelerometerX(void) { return SimAccelerometerData[0].x; }
-double HAL_GetAccelerometerY(void) { return SimAccelerometerData[0].y; }
-double HAL_GetAccelerometerZ(void) { return SimAccelerometerData[0].z; }
+double HAL_GetAccelerometerX(void) {
+  return SimAccelerometerData[0].x;
+}
+double HAL_GetAccelerometerY(void) {
+  return SimAccelerometerData[0].y;
+}
+double HAL_GetAccelerometerZ(void) {
+  return SimAccelerometerData[0].z;
+}
 }  // extern "C"
diff --git a/hal/src/main/native/sim/AddressableLED.cpp b/hal/src/main/native/sim/AddressableLED.cpp
index 70d3f6f..75a09fb 100644
--- a/hal/src/main/native/sim/AddressableLED.cpp
+++ b/hal/src/main/native/sim/AddressableLED.cpp
@@ -1,14 +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.
 
 #include "hal/AddressableLED.h"
 
+#include <fmt/format.h>
+
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/Errors.h"
 #include "hal/handles/HandlesInternal.h"
@@ -27,8 +27,7 @@
                              kNumAddressableLEDs,
                              HAL_HandleEnum::AddressableLED>* ledHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAddressableLED() {
   static LimitedHandleResource<HAL_AddressableLEDHandle, AddressableLED,
                                kNumAddressableLEDs,
@@ -36,8 +35,7 @@
       dcH;
   ledHandles = &dcH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
@@ -86,7 +84,9 @@
 void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {
   auto led = ledHandles->Get(handle);
   ledHandles->Free(handle);
-  if (!led) return;
+  if (!led) {
+    return;
+  }
   SimAddressableLEDData[led->index].running = false;
   SimAddressableLEDData[led->index].initialized = false;
 }
@@ -113,8 +113,13 @@
     *status = HAL_HANDLE_ERROR;
     return;
   }
-  if (length > HAL_kAddressableLEDMaxLength) {
+  if (length > HAL_kAddressableLEDMaxLength || length < 0) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format(
+            "LED length must be less than or equal to {}. {} was requested",
+            HAL_kAddressableLEDMaxLength, length));
     return;
   }
   SimAddressableLEDData[led->index].length = length;
@@ -130,6 +135,11 @@
   }
   if (length > SimAddressableLEDData[led->index].length) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format(
+            "Data length must be less than or equal to {}. {} was requested",
+            SimAddressableLEDData[led->index].length, length));
     return;
   }
   SimAddressableLEDData[led->index].SetData(data, length);
diff --git a/hal/src/main/native/sim/AnalogAccumulator.cpp b/hal/src/main/native/sim/AnalogAccumulator.cpp
index 537aa15..0f65b13 100644
--- a/hal/src/main/native/sim/AnalogAccumulator.cpp
+++ b/hal/src/main/native/sim/AnalogAccumulator.cpp
@@ -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.
 
 #include "hal/AnalogAccumulator.h"
 
@@ -12,11 +9,9 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogAccumulator() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 HAL_Bool HAL_IsAccumulatorChannel(HAL_AnalogInputHandle analogPortHandle,
@@ -27,7 +22,9 @@
     return false;
   }
   for (int32_t i = 0; i < kNumAccumulators; i++) {
-    if (port->channel == kAccumulatorChannels[i]) return true;
+    if (port->channel == kAccumulatorChannels[i]) {
+      return true;
+    }
   }
   return false;
 }
diff --git a/hal/src/main/native/sim/AnalogGyro.cpp b/hal/src/main/native/sim/AnalogGyro.cpp
index 9666f4a..3efca20 100644
--- a/hal/src/main/native/sim/AnalogGyro.cpp
+++ b/hal/src/main/native/sim/AnalogGyro.cpp
@@ -1,13 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/AnalogGyro.h"
 
+#include <string>
+
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/AnalogAccumulator.h"
 #include "hal/Errors.h"
@@ -18,6 +18,7 @@
 struct AnalogGyro {
   HAL_AnalogInputHandle handle;
   uint8_t index;
+  std::string previousAllocation;
 };
 }  // namespace
 
@@ -26,41 +27,43 @@
 static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
                              HAL_HandleEnum::AnalogGyro>* analogGyroHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogGyro() {
   static IndexedHandleResource<HAL_GyroHandle, AnalogGyro, kNumAccumulators,
                                HAL_HandleEnum::AnalogGyro>
       agH;
   analogGyroHandles = &agH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle analogHandle,
+                                        const char* allocationLocation,
                                         int32_t* status) {
   hal::init::CheckInit();
+  // Handle will be type checked by HAL_IsAccumulatorChannel
+  int16_t channel = getHandleIndex(analogHandle);
   if (!HAL_IsAccumulatorChannel(analogHandle, status)) {
     if (*status == 0) {
       *status = HAL_INVALID_ACCUMULATOR_CHANNEL;
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro",
+                                       0, kNumAccumulators, channel);
     }
     return HAL_kInvalidHandle;
   }
 
-  // handle known to be correct, so no need to type check
-  int16_t channel = getHandleIndex(analogHandle);
+  HAL_GyroHandle handle;
+  auto gyro = analogGyroHandles->Allocate(channel, &handle, status);
 
-  auto handle = analogGyroHandles->Allocate(channel, status);
-
-  if (*status != 0)
+  if (*status != 0) {
+    if (gyro) {
+      hal::SetLastErrorPreviouslyAllocated(status, "Analog Gyro", channel,
+                                           gyro->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Gyro",
+                                       0, kNumAccumulators, channel);
+    }
     return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
-
-  // Initialize port structure
-  auto gyro = analogGyroHandles->Get(handle);
-  if (gyro == nullptr) {  // would only error on thread issue
-    *status = HAL_HANDLE_ERROR;
-    return HAL_kInvalidHandle;
   }
 
   gyro->handle = analogHandle;
@@ -68,6 +71,8 @@
 
   SimAnalogGyroData[channel].initialized = true;
 
+  gyro->previousAllocation = allocationLocation ? allocationLocation : "";
+
   return handle;
 }
 
@@ -78,7 +83,9 @@
 void HAL_FreeAnalogGyro(HAL_GyroHandle handle) {
   auto gyro = analogGyroHandles->Get(handle);
   analogGyroHandles->Free(handle);
-  if (gyro == nullptr) return;
+  if (gyro == nullptr) {
+    return;
+  }
   SimAnalogGyroData[gyro->index].initialized = false;
 }
 
diff --git a/hal/src/main/native/sim/AnalogInput.cpp b/hal/src/main/native/sim/AnalogInput.cpp
index 8ecde74..4697dc2 100644
--- a/hal/src/main/native/sim/AnalogInput.cpp
+++ b/hal/src/main/native/sim/AnalogInput.cpp
@@ -1,14 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/AnalogInput.h"
 
 #include "AnalogInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/AnalogAccumulator.h"
 #include "hal/handles/HandlesInternal.h"
@@ -16,32 +14,35 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogInput() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
-HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle,
-                                                    int32_t* status) {
+HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(
+    HAL_PortHandle portHandle, const char* allocationLocation,
+    int32_t* status) {
   hal::init::CheckInit();
   int16_t channel = getPortHandleChannel(portHandle);
-  if (channel == InvalidHandleIndex) {
-    *status = PARAMETER_OUT_OF_RANGE;
+  if (channel == InvalidHandleIndex || channel >= kNumAnalogInputs) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Input",
+                                     0, kNumAnalogInputs, channel);
     return HAL_kInvalidHandle;
   }
 
-  HAL_AnalogInputHandle handle = analogInputHandles->Allocate(channel, status);
+  HAL_AnalogInputHandle handle;
+  auto analog_port = analogInputHandles->Allocate(channel, &handle, status);
 
-  if (*status != 0)
+  if (*status != 0) {
+    if (analog_port) {
+      hal::SetLastErrorPreviouslyAllocated(status, "Analog Input", channel,
+                                           analog_port->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Input",
+                                       0, kNumAnalogInputs, channel);
+    }
     return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
-
-  // Initialize port structure
-  auto analog_port = analogInputHandles->Get(handle);
-  if (analog_port == nullptr) {  // would only error on thread issue
-    *status = HAL_HANDLE_ERROR;
-    return HAL_kInvalidHandle;
   }
 
   analog_port->channel = static_cast<uint8_t>(channel);
@@ -55,18 +56,25 @@
   SimAnalogInData[channel].accumulatorInitialized = false;
   SimAnalogInData[channel].simDevice = 0;
 
+  analog_port->previousAllocation =
+      allocationLocation ? allocationLocation : "";
+
   return handle;
 }
 void HAL_FreeAnalogInputPort(HAL_AnalogInputHandle analogPortHandle) {
   auto port = analogInputHandles->Get(analogPortHandle);
   // no status, so no need to check for a proper free.
   analogInputHandles->Free(analogPortHandle);
-  if (port == nullptr) return;
+  if (port == nullptr) {
+    return;
+  }
   SimAnalogInData[port->channel].initialized = false;
   SimAnalogInData[port->channel].accumulatorInitialized = false;
 }
 
-HAL_Bool HAL_CheckAnalogModule(int32_t module) { return module == 1; }
+HAL_Bool HAL_CheckAnalogModule(int32_t module) {
+  return module == 1;
+}
 
 HAL_Bool HAL_CheckAnalogInputChannel(int32_t channel) {
   return channel < kNumAnalogInputs && channel >= 0;
@@ -75,14 +83,18 @@
 void HAL_SetAnalogInputSimDevice(HAL_AnalogInputHandle handle,
                                  HAL_SimDeviceHandle device) {
   auto port = analogInputHandles->Get(handle);
-  if (port == nullptr) return;
+  if (port == nullptr) {
+    return;
+  }
   SimAnalogInData[port->channel].simDevice = device;
 }
 
 void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status) {
   // No op
 }
-double HAL_GetAnalogSampleRate(int32_t* status) { return kDefaultSampleRate; }
+double HAL_GetAnalogSampleRate(int32_t* status) {
+  return kDefaultSampleRate;
+}
 void HAL_SetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
                               int32_t bits, int32_t* status) {
   auto port = analogInputHandles->Get(analogPortHandle);
diff --git a/hal/src/main/native/sim/AnalogInternal.cpp b/hal/src/main/native/sim/AnalogInternal.cpp
index 820dc97..9b2c225 100644
--- a/hal/src/main/native/sim/AnalogInternal.cpp
+++ b/hal/src/main/native/sim/AnalogInternal.cpp
@@ -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.
 
 #include "AnalogInternal.h"
 
@@ -15,13 +12,11 @@
                       HAL_HandleEnum::AnalogInput>* analogInputHandles;
 }  // namespace hal
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogInternal() {
   static IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort,
                                kNumAnalogInputs, HAL_HandleEnum::AnalogInput>
       aiH;
   analogInputHandles = &aiH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
diff --git a/hal/src/main/native/sim/AnalogInternal.h b/hal/src/main/native/sim/AnalogInternal.h
index f4633f9..89cb359 100644
--- a/hal/src/main/native/sim/AnalogInternal.h
+++ b/hal/src/main/native/sim/AnalogInternal.h
@@ -1,14 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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 <stdint.h>
 
+#include <string>
+
 #include "PortsInternal.h"
 #include "hal/handles/HandlesInternal.h"
 #include "hal/handles/IndexedHandleResource.h"
@@ -23,6 +22,7 @@
 struct AnalogPort {
   uint8_t channel;
   bool isAccumulator;
+  std::string previousAllocation;
 };
 
 extern IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort,
diff --git a/hal/src/main/native/sim/AnalogOutput.cpp b/hal/src/main/native/sim/AnalogOutput.cpp
index 2e3a348..d04224a 100644
--- a/hal/src/main/native/sim/AnalogOutput.cpp
+++ b/hal/src/main/native/sim/AnalogOutput.cpp
@@ -1,13 +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.
 
 #include "hal/AnalogOutput.h"
 
+#include <string>
+
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/Errors.h"
 #include "hal/handles/HandlesInternal.h"
@@ -19,6 +19,7 @@
 namespace {
 struct AnalogOutput {
   uint8_t channel;
+  std::string previousAllocation;
 };
 }  // namespace
 
@@ -26,50 +27,58 @@
                              kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>*
     analogOutputHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogOutput() {
   static IndexedHandleResource<HAL_AnalogOutputHandle, AnalogOutput,
                                kNumAnalogOutputs, HAL_HandleEnum::AnalogOutput>
       aoH;
   analogOutputHandles = &aoH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
-HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle,
-                                                      int32_t* status) {
+HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(
+    HAL_PortHandle portHandle, const char* allocationLocation,
+    int32_t* status) {
   hal::init::CheckInit();
   int16_t channel = getPortHandleChannel(portHandle);
-  if (channel == InvalidHandleIndex) {
-    *status = PARAMETER_OUT_OF_RANGE;
+  if (channel == InvalidHandleIndex || channel >= kNumAnalogOutputs) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Analog Output",
+                                     0, kNumAnalogOutputs, channel);
     return HAL_kInvalidHandle;
   }
 
-  HAL_AnalogOutputHandle handle =
-      analogOutputHandles->Allocate(channel, status);
+  HAL_AnalogOutputHandle handle;
+  auto port = analogOutputHandles->Allocate(channel, &handle, status);
 
-  if (*status != 0)
+  if (*status != 0) {
+    if (port) {
+      hal::SetLastErrorPreviouslyAllocated(status, "Analog Output", channel,
+                                           port->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status,
+                                       "Invalid Index for Analog Output", 0,
+                                       kNumAnalogOutputs, channel);
+    }
     return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
-
-  auto port = analogOutputHandles->Get(handle);
-  if (port == nullptr) {  // would only error on thread issue
-    *status = HAL_HANDLE_ERROR;
-    return HAL_kInvalidHandle;
   }
 
   port->channel = static_cast<uint8_t>(channel);
 
   // Initialize sim analog input
   SimAnalogOutData[channel].initialized = true;
+
+  port->previousAllocation = allocationLocation ? allocationLocation : "";
   return handle;
 }
 
 void HAL_FreeAnalogOutputPort(HAL_AnalogOutputHandle analogOutputHandle) {
   // no status, so no need to check for a proper free.
   auto port = analogOutputHandles->Get(analogOutputHandle);
-  if (port == nullptr) return;
+  if (port == nullptr) {
+    return;
+  }
   analogOutputHandles->Free(analogOutputHandle);
   SimAnalogOutData[port->channel].initialized = false;
 }
diff --git a/hal/src/main/native/sim/AnalogTrigger.cpp b/hal/src/main/native/sim/AnalogTrigger.cpp
index 62bfebc..50c4ab4 100644
--- a/hal/src/main/native/sim/AnalogTrigger.cpp
+++ b/hal/src/main/native/sim/AnalogTrigger.cpp
@@ -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.
 
 #include "hal/AnalogTrigger.h"
 
@@ -31,8 +28,7 @@
                              kNumAnalogTriggers, HAL_HandleEnum::AnalogTrigger>*
     analogTriggerHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogTrigger() {
   static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
                                kNumAnalogTriggers,
@@ -40,8 +36,7 @@
       atH;
   analogTriggerHandles = &atH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 int32_t hal::GetAnalogTriggerInputIndex(HAL_AnalogTriggerHandle handle,
                                         int32_t* status) {
@@ -102,7 +97,9 @@
                             int32_t* status) {
   auto trigger = analogTriggerHandles->Get(analogTriggerHandle);
   analogTriggerHandles->Free(analogTriggerHandle);
-  if (trigger == nullptr) return;
+  if (trigger == nullptr) {
+    return;
+  }
   SimAnalogTriggerData[trigger->index].initialized = false;
   // caller owns the analog input handle.
 }
@@ -131,10 +128,14 @@
 
   double trigLower =
       GetAnalogValueToVoltage(trigger->analogHandle, lower, status);
-  if (status != 0) return;
+  if (status != nullptr) {
+    return;
+  }
   double trigUpper =
       GetAnalogValueToVoltage(trigger->analogHandle, upper, status);
-  if (status != 0) return;
+  if (status != nullptr) {
+    return;
+  }
 
   SimAnalogTriggerData[trigger->index].triggerUpperBound = trigUpper;
   SimAnalogTriggerData[trigger->index].triggerLowerBound = trigLower;
diff --git a/hal/src/main/native/sim/CAN.cpp b/hal/src/main/native/sim/CAN.cpp
index 1e7af73..93a422b 100644
--- a/hal/src/main/native/sim/CAN.cpp
+++ b/hal/src/main/native/sim/CAN.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "hal/CAN.h"
 
@@ -11,11 +8,9 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeCAN() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
diff --git a/hal/src/main/native/sim/CANAPI.cpp b/hal/src/main/native/sim/CANAPI.cpp
index c410dea..4d733bb 100644
--- a/hal/src/main/native/sim/CANAPI.cpp
+++ b/hal/src/main/native/sim/CANAPI.cpp
@@ -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.
 
 #include "hal/CANAPI.h"
 
diff --git a/hal/src/main/native/sim/CANAPIInternal.h b/hal/src/main/native/sim/CANAPIInternal.h
index 074f682..10e64ef 100644
--- a/hal/src/main/native/sim/CANAPIInternal.h
+++ b/hal/src/main/native/sim/CANAPIInternal.h
@@ -1,16 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "hal/Types.h"
 
-namespace hal {
-namespace can {
+namespace hal::can {
 int32_t GetCANModuleFromHandle(HAL_CANHandle handle, int32_t* status);
-}  // namespace can
-}  // namespace hal
+}  // namespace hal::can
diff --git a/hal/src/main/native/sim/CTREPCM.cpp b/hal/src/main/native/sim/CTREPCM.cpp
new file mode 100644
index 0000000..93f9135
--- /dev/null
+++ b/hal/src/main/native/sim/CTREPCM.cpp
@@ -0,0 +1,218 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "hal/CTREPCM.h"
+
+#include "HALInitializer.h"
+#include "HALInternal.h"
+#include "PortsInternal.h"
+#include "hal/CANAPI.h"
+#include "hal/Errors.h"
+#include "hal/handles/IndexedHandleResource.h"
+#include "mockdata/CTREPCMDataInternal.h"
+
+using namespace hal;
+
+namespace {
+struct PCM {
+  int32_t module;
+  wpi::mutex lock;
+  std::string previousAllocation;
+};
+}  // namespace
+
+static IndexedHandleResource<HAL_CTREPCMHandle, PCM, kNumCTREPCMModules,
+                             HAL_HandleEnum::CTREPCM>* pcmHandles;
+
+namespace hal::init {
+void InitializeCTREPCM() {
+  static IndexedHandleResource<HAL_CTREPCMHandle, PCM, kNumCTREPCMModules,
+                               HAL_HandleEnum::CTREPCM>
+      pH;
+  pcmHandles = &pH;
+}
+}  // namespace hal::init
+
+HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t module,
+                                        const char* allocationLocation,
+                                        int32_t* status) {
+  hal::init::CheckInit();
+
+  HAL_CTREPCMHandle handle;
+  auto pcm = pcmHandles->Allocate(module, &handle, status);
+
+  if (*status != 0) {
+    if (pcm) {
+      hal::SetLastErrorPreviouslyAllocated(status, "CTRE PCM", module,
+                                           pcm->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for CTRE PCM", 0,
+                                       kNumCTREPCMModules, module);
+    }
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+  }
+
+  pcm->previousAllocation = allocationLocation ? allocationLocation : "";
+  pcm->module = module;
+
+  SimCTREPCMData[module].initialized = true;
+  // Enable closed loop
+  SimCTREPCMData[module].closedLoopEnabled = true;
+
+  return handle;
+}
+
+void HAL_FreeCTREPCM(HAL_CTREPCMHandle handle) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    pcmHandles->Free(handle);
+    return;
+  }
+  SimCTREPCMData[pcm->module].initialized = false;
+  pcmHandles->Free(handle);
+}
+
+HAL_Bool HAL_CheckCTREPCMSolenoidChannel(int32_t channel) {
+  return channel < kNumCTRESolenoidChannels && channel >= 0;
+}
+
+HAL_Bool HAL_GetCTREPCMCompressor(HAL_CTREPCMHandle handle, int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimCTREPCMData[pcm->module].compressorOn;
+}
+
+void HAL_SetCTREPCMClosedLoopControl(HAL_CTREPCMHandle handle, HAL_Bool enabled,
+                                     int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimCTREPCMData[pcm->module].closedLoopEnabled = enabled;
+}
+
+HAL_Bool HAL_GetCTREPCMClosedLoopControl(HAL_CTREPCMHandle handle,
+                                         int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimCTREPCMData[pcm->module].closedLoopEnabled;
+}
+
+HAL_Bool HAL_GetCTREPCMPressureSwitch(HAL_CTREPCMHandle handle,
+                                      int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimCTREPCMData[pcm->module].pressureSwitch;
+}
+
+double HAL_GetCTREPCMCompressorCurrent(HAL_CTREPCMHandle handle,
+                                       int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimCTREPCMData[pcm->module].compressorCurrent;
+}
+
+HAL_Bool HAL_GetCTREPCMCompressorCurrentTooHighFault(HAL_CTREPCMHandle handle,
+                                                     int32_t* status) {
+  return false;
+}
+
+HAL_Bool HAL_GetCTREPCMCompressorCurrentTooHighStickyFault(
+    HAL_CTREPCMHandle handle, int32_t* status) {
+  return false;
+}
+
+HAL_Bool HAL_GetCTREPCMCompressorShortedStickyFault(HAL_CTREPCMHandle handle,
+                                                    int32_t* status) {
+  return false;
+}
+
+HAL_Bool HAL_GetCTREPCMCompressorShortedFault(HAL_CTREPCMHandle handle,
+                                              int32_t* status) {
+  return false;
+}
+
+HAL_Bool HAL_GetCTREPCMCompressorNotConnectedStickyFault(
+    HAL_CTREPCMHandle handle, int32_t* status) {
+  return false;
+}
+
+HAL_Bool HAL_GetCTREPCMCompressorNotConnectedFault(HAL_CTREPCMHandle handle,
+                                                   int32_t* status) {
+  return false;
+}
+
+int32_t HAL_GetCTREPCMSolenoids(HAL_CTREPCMHandle handle, int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  std::scoped_lock lock{pcm->lock};
+  auto& data = SimCTREPCMData[pcm->module].solenoidOutput;
+  uint8_t ret = 0;
+  for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
+    ret |= (data[i] << i);
+  }
+  return ret;
+}
+void HAL_SetCTREPCMSolenoids(HAL_CTREPCMHandle handle, int32_t mask,
+                             int32_t values, int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  auto& data = SimCTREPCMData[pcm->module].solenoidOutput;
+  std::scoped_lock lock{pcm->lock};
+  for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
+    auto indexMask = (1 << i);
+    if ((mask & indexMask) != 0) {
+      data[i] = (values & indexMask) != 0;
+    }
+  }
+}
+
+int32_t HAL_GetCTREPCMSolenoidDisabledList(HAL_CTREPCMHandle handle,
+                                           int32_t* status) {
+  return 0;
+}
+
+HAL_Bool HAL_GetCTREPCMSolenoidVoltageStickyFault(HAL_CTREPCMHandle handle,
+                                                  int32_t* status) {
+  return false;
+}
+
+HAL_Bool HAL_GetCTREPCMSolenoidVoltageFault(HAL_CTREPCMHandle handle,
+                                            int32_t* status) {
+  return false;
+}
+
+void HAL_ClearAllCTREPCMStickyFaults(HAL_CTREPCMHandle handle,
+                                     int32_t* status) {}
+
+void HAL_FireCTREPCMOneShot(HAL_CTREPCMHandle handle, int32_t index,
+                            int32_t* status) {}
+void HAL_SetCTREPCMOneShotDuration(HAL_CTREPCMHandle handle, int32_t index,
+                                   int32_t durMs, int32_t* status) {}
diff --git a/hal/src/main/native/sim/Compressor.cpp b/hal/src/main/native/sim/Compressor.cpp
deleted file mode 100644
index b5c5867..0000000
--- a/hal/src/main/native/sim/Compressor.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* 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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "hal/Compressor.h"
-
-#include "HALInitializer.h"
-#include "PortsInternal.h"
-#include "hal/Errors.h"
-#include "hal/handles/HandlesInternal.h"
-#include "mockdata/PCMDataInternal.h"
-
-using namespace hal;
-
-namespace hal {
-namespace init {
-void InitializeCompressor() {}
-}  // namespace init
-}  // namespace hal
-
-extern "C" {
-
-HAL_CompressorHandle HAL_InitializeCompressor(int32_t module, int32_t* status) {
-  hal::init::CheckInit();
-  // As compressors can have unlimited objects, just create a
-  // handle with the module number as the index.
-
-  SimPCMData[module].compressorInitialized = true;
-  return (HAL_CompressorHandle)createHandle(static_cast<int16_t>(module),
-                                            HAL_HandleEnum::Compressor, 0);
-}
-
-HAL_Bool HAL_CheckCompressorModule(int32_t module) {
-  return module < kNumPCMModules && module >= 0;
-}
-
-HAL_Bool HAL_GetCompressor(HAL_CompressorHandle compressorHandle,
-                           int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-
-  return SimPCMData[index].compressorOn;
-}
-
-void HAL_SetCompressorClosedLoopControl(HAL_CompressorHandle compressorHandle,
-                                        HAL_Bool value, int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  SimPCMData[index].closedLoopEnabled = value;
-}
-
-HAL_Bool HAL_GetCompressorClosedLoopControl(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-
-  return SimPCMData[index].closedLoopEnabled;
-}
-
-HAL_Bool HAL_GetCompressorPressureSwitch(HAL_CompressorHandle compressorHandle,
-                                         int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-
-  return SimPCMData[index].pressureSwitch;
-}
-
-double HAL_GetCompressorCurrent(HAL_CompressorHandle compressorHandle,
-                                int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return 0;
-  }
-
-  return SimPCMData[index].compressorCurrent;
-}
-HAL_Bool HAL_GetCompressorCurrentTooHighFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  return false;
-}
-HAL_Bool HAL_GetCompressorCurrentTooHighStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  return false;
-}
-HAL_Bool HAL_GetCompressorShortedStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  return false;
-}
-HAL_Bool HAL_GetCompressorShortedFault(HAL_CompressorHandle compressorHandle,
-                                       int32_t* status) {
-  return false;
-}
-HAL_Bool HAL_GetCompressorNotConnectedStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  return false;
-}
-HAL_Bool HAL_GetCompressorNotConnectedFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  return false;
-}
-}  // extern "C"
diff --git a/hal/src/main/native/sim/Constants.cpp b/hal/src/main/native/sim/Constants.cpp
index 64cb52b..6c1361e 100644
--- a/hal/src/main/native/sim/Constants.cpp
+++ b/hal/src/main/native/sim/Constants.cpp
@@ -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.
 
 #include "hal/Constants.h"
 
@@ -11,11 +8,9 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeConstants() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 int32_t HAL_GetSystemClockTicksPerMicrosecond(void) {
diff --git a/hal/src/main/native/sim/ConstantsInternal.h b/hal/src/main/native/sim/ConstantsInternal.h
index c3a6e8f..f4af049 100644
--- a/hal/src/main/native/sim/ConstantsInternal.h
+++ b/hal/src/main/native/sim/ConstantsInternal.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
 
diff --git a/hal/src/main/native/sim/Counter.cpp b/hal/src/main/native/sim/Counter.cpp
index f0ea1c4..a56b646 100644
--- a/hal/src/main/native/sim/Counter.cpp
+++ b/hal/src/main/native/sim/Counter.cpp
@@ -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.
 
 #include "hal/Counter.h"
 
@@ -19,16 +16,14 @@
                       HAL_HandleEnum::Counter>* counterHandles;
 }  // namespace hal
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeCounter() {
   static LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
                                HAL_HandleEnum::Counter>
       cH;
   counterHandles = &cH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 HAL_CounterHandle HAL_InitializeCounter(HAL_Counter_Mode mode, int32_t* index,
diff --git a/hal/src/main/native/sim/CounterInternal.h b/hal/src/main/native/sim/CounterInternal.h
index 70fbe54..81433fa 100644
--- a/hal/src/main/native/sim/CounterInternal.h
+++ b/hal/src/main/native/sim/CounterInternal.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/hal/src/main/native/sim/DIO.cpp b/hal/src/main/native/sim/DIO.cpp
index f6347d9..1b744a1 100644
--- a/hal/src/main/native/sim/DIO.cpp
+++ b/hal/src/main/native/sim/DIO.cpp
@@ -1,14 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/DIO.h"
 
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/handles/HandlesInternal.h"
 #include "hal/handles/LimitedHandleResource.h"
@@ -21,8 +19,7 @@
                              kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>*
     digitalPWMHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDIO() {
   static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
                                kNumDigitalPWMOutputs,
@@ -30,32 +27,38 @@
       dpH;
   digitalPWMHandles = &dpH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
 HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
-                                        HAL_Bool input, int32_t* status) {
+                                        HAL_Bool input,
+                                        const char* allocationLocation,
+                                        int32_t* status) {
   hal::init::CheckInit();
-  if (*status != 0) return HAL_kInvalidHandle;
 
   int16_t channel = getPortHandleChannel(portHandle);
   if (channel == InvalidHandleIndex) {
-    *status = PARAMETER_OUT_OF_RANGE;
+    *status = RESOURCE_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
+                                     kNumDigitalChannels, channel);
     return HAL_kInvalidHandle;
   }
 
-  auto handle =
-      digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, status);
+  HAL_DigitalHandle handle;
 
-  if (*status != 0)
+  auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO,
+                                              &handle, status);
+
+  if (*status != 0) {
+    if (port) {
+      hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
+                                           port->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
+                                       kNumDigitalChannels, channel);
+    }
     return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
-
-  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
-  if (port == nullptr) {  // would only occur on thread issue.
-    *status = HAL_HANDLE_ERROR;
-    return HAL_kInvalidHandle;
   }
 
   port->channel = static_cast<uint8_t>(channel);
@@ -63,6 +66,7 @@
   SimDIOData[channel].initialized = true;
   SimDIOData[channel].isInput = input;
   SimDIOData[channel].simDevice = 0;
+  port->previousAllocation = allocationLocation ? allocationLocation : "";
 
   return handle;
 }
@@ -75,13 +79,17 @@
   auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
   // no status, so no need to check for a proper free.
   digitalChannelHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
-  if (port == nullptr) return;
+  if (port == nullptr) {
+    return;
+  }
   SimDIOData[port->channel].initialized = false;
 }
 
 void HAL_SetDIOSimDevice(HAL_DigitalHandle handle, HAL_SimDeviceHandle device) {
   auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
-  if (port == nullptr) return;
+  if (port == nullptr) {
+    return;
+  }
   SimDIOData[port->channel].simDevice = device;
 }
 
@@ -107,7 +115,9 @@
 void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status) {
   auto port = digitalPWMHandles->Get(pwmGenerator);
   digitalPWMHandles->Free(pwmGenerator);
-  if (port == nullptr) return;
+  if (port == nullptr) {
+    return;
+  }
   int32_t id = *port;
   SimDigitalPWMData[id].initialized = false;
 }
@@ -132,8 +142,12 @@
     return;
   }
   int32_t id = *port;
-  if (dutyCycle > 1.0) dutyCycle = 1.0;
-  if (dutyCycle < 0.0) dutyCycle = 0.0;
+  if (dutyCycle > 1.0) {
+    dutyCycle = 1.0;
+  }
+  if (dutyCycle < 0.0) {
+    dutyCycle = 0.0;
+  }
   SimDigitalPWMData[id].dutyCycle = dutyCycle;
 }
 
@@ -156,7 +170,14 @@
     return;
   }
   if (value != 0 && value != 1) {
-    if (value != 0) value = 1;
+    if (value != 0) {
+      value = 1;
+    }
+  }
+  if (SimDIOData[port->channel].isInput) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, "Cannot set output of an input channel");
+    return;
   }
   SimDIOData[port->channel].value = value;
 }
@@ -179,8 +200,12 @@
     return false;
   }
   HAL_Bool value = SimDIOData[port->channel].value;
-  if (value > 1) value = 1;
-  if (value < 0) value = 0;
+  if (value > 1) {
+    value = 1;
+  }
+  if (value < 0) {
+    value = 0;
+  }
   return value;
 }
 
@@ -191,8 +216,12 @@
     return false;
   }
   HAL_Bool value = SimDIOData[port->channel].isInput;
-  if (value > 1) value = 1;
-  if (value < 0) value = 0;
+  if (value > 1) {
+    value = 1;
+  }
+  if (value < 0) {
+    value = 0;
+  }
   return value;
 }
 
diff --git a/hal/src/main/native/sim/DMA.cpp b/hal/src/main/native/sim/DMA.cpp
index cea5a29..c000ac5 100644
--- a/hal/src/main/native/sim/DMA.cpp
+++ b/hal/src/main/native/sim/DMA.cpp
@@ -1,18 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "hal/DMA.h"
 
 extern "C" {
-HAL_DMAHandle HAL_InitializeDMA(int32_t* status) { return HAL_kInvalidHandle; }
+HAL_DMAHandle HAL_InitializeDMA(int32_t* status) {
+  return HAL_kInvalidHandle;
+}
 void HAL_FreeDMA(HAL_DMAHandle handle) {}
 
 void HAL_SetDMAPause(HAL_DMAHandle handle, HAL_Bool pause, int32_t* status) {}
-void HAL_SetDMARate(HAL_DMAHandle handle, int32_t cycles, int32_t* status) {}
+void HAL_SetDMATimedTrigger(HAL_DMAHandle handle, double periodSeconds,
+                            int32_t* status) {}
+void HAL_SetDMATimedTriggerCycles(HAL_DMAHandle handle, uint32_t cycles,
+                                  int32_t* status) {}
 
 void HAL_AddDMAEncoder(HAL_DMAHandle handle, HAL_EncoderHandle encoderHandle,
                        int32_t* status) {}
@@ -41,28 +43,36 @@
                          HAL_DutyCycleHandle dutyCycleHandle, int32_t* status) {
 }
 
-void HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
-                               HAL_Handle digitalSourceHandle,
-                               HAL_AnalogTriggerType analogTriggerType,
-                               HAL_Bool rising, HAL_Bool falling,
-                               int32_t* status) {}
+int32_t HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
+                                  HAL_Handle digitalSourceHandle,
+                                  HAL_AnalogTriggerType analogTriggerType,
+                                  HAL_Bool rising, HAL_Bool falling,
+                                  int32_t* status) {
+  return 0;
+}
+
+void HAL_ClearDMASensors(HAL_DMAHandle handle, int32_t* status) {}
+void HAL_ClearDMAExternalTriggers(HAL_DMAHandle handle, int32_t* status) {}
 
 void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status) {}
 void HAL_StopDMA(HAL_DMAHandle handle, int32_t* status) {}
 
-void* HAL_GetDMADirectPointer(HAL_DMAHandle handle) { return nullptr; }
+void* HAL_GetDMADirectPointer(HAL_DMAHandle handle) {
+  return nullptr;
+}
 
 enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
                                          HAL_DMASample* dmaSample,
-                                         int32_t timeoutMs,
+                                         double timeoutSeconds,
                                          int32_t* remainingOut,
                                          int32_t* status) {
   return HAL_DMA_ERROR;
 }
 
 enum HAL_DMAReadStatus HAL_ReadDMA(HAL_DMAHandle handle,
-                                   HAL_DMASample* dmaSample, int32_t timeoutMs,
-                                   int32_t* remainingOut, int32_t* status) {
+                                   HAL_DMASample* dmaSample,
+                                   double timeoutSeconds, int32_t* remainingOut,
+                                   int32_t* status) {
   return HAL_DMA_ERROR;
 }
 
diff --git a/hal/src/main/native/sim/DigitalInternal.cpp b/hal/src/main/native/sim/DigitalInternal.cpp
index db6455a..b7c1d2f 100644
--- a/hal/src/main/native/sim/DigitalInternal.cpp
+++ b/hal/src/main/native/sim/DigitalInternal.cpp
@@ -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.
 
 #include "DigitalInternal.h"
 
@@ -55,7 +52,9 @@
   }
 }
 
-int32_t remapMXPChannel(int32_t channel) { return channel - 10; }
+int32_t remapMXPChannel(int32_t channel) {
+  return channel - 10;
+}
 
 int32_t remapMXPPWMChannel(int32_t channel) {
   if (channel < 14) {
diff --git a/hal/src/main/native/sim/DigitalInternal.h b/hal/src/main/native/sim/DigitalInternal.h
index d169c8a..cd1ac5f 100644
--- a/hal/src/main/native/sim/DigitalInternal.h
+++ b/hal/src/main/native/sim/DigitalInternal.h
@@ -1,14 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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 <stdint.h>
 
+#include <string>
+
 #include "PortsInternal.h"
 #include "hal/AnalogTrigger.h"
 #include "hal/handles/DigitalHandleResource.h"
@@ -59,6 +58,7 @@
   int32_t centerPwm = 0;
   int32_t deadbandMinPwm = 0;
   int32_t minPwm = 0;
+  std::string previousAllocation;
 };
 
 extern DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
diff --git a/hal/src/main/native/sim/DriverStation.cpp b/hal/src/main/native/sim/DriverStation.cpp
index aef8556..723cdac 100644
--- a/hal/src/main/native/sim/DriverStation.cpp
+++ b/hal/src/main/native/sim/DriverStation.cpp
@@ -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.
 
 #include "hal/DriverStation.h"
 
@@ -16,9 +13,9 @@
 #include <cstring>
 #include <string>
 
+#include <fmt/format.h>
 #include <wpi/condition_variable.h>
 #include <wpi/mutex.h>
-#include <wpi/raw_ostream.h>
 
 #include "HALInitializer.h"
 #include "hal/cpp/fpga_clock.h"
@@ -34,14 +31,12 @@
 static std::atomic<HALSIM_SendConsoleLineHandler> sendConsoleLineHandler{
     nullptr};
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDriverStation() {
   static wpi::condition_variable nddaC;
   newDSDataAvailableCond = &nddaC;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 using namespace hal;
 
@@ -59,9 +54,10 @@
                       const char* details, const char* location,
                       const char* callStack, HAL_Bool printMsg) {
   auto errorHandler = sendErrorHandler.load();
-  if (errorHandler)
+  if (errorHandler) {
     return errorHandler(isError, errorCode, isLVCode, details, location,
                         callStack, printMsg);
+  }
   // Avoid flooding console by keeping track of previous 5 error
   // messages and only printing again if they're longer than 1 second old.
   static constexpr int KEEP_MSGS = 5;
@@ -79,20 +75,24 @@
   auto curTime = fpga_clock::now();
   int i;
   for (i = 0; i < KEEP_MSGS; ++i) {
-    if (prevMsg[i] == details) break;
+    if (prevMsg[i] == details) {
+      break;
+    }
   }
   int retval = 0;
   if (i == KEEP_MSGS || (curTime - prevMsgTime[i]) >= std::chrono::seconds(1)) {
     printMsg = true;
     if (printMsg) {
+      fmt::memory_buffer buf;
       if (location && location[0] != '\0') {
-        std::fprintf(stderr, "%s at %s: ", isError ? "Error" : "Warning",
-                     location);
+        fmt::format_to(fmt::appender{buf},
+                       "{} at {}: ", isError ? "Error" : "Warning", location);
       }
-      std::fprintf(stderr, "%s\n", details);
+      fmt::format_to(fmt::appender{buf}, "{}\n", details);
       if (callStack && callStack[0] != '\0') {
-        std::fprintf(stderr, "%s\n", callStack);
+        fmt::format_to(fmt::appender{buf}, "{}\n", callStack);
       }
+      std::fwrite(buf.data(), buf.size(), 1, stderr);
     }
     if (i == KEEP_MSGS) {
       // replace the oldest one
@@ -116,12 +116,13 @@
   if (handler) {
     return handler(line);
   }
-  wpi::outs() << line << "\n";
-  wpi::outs().flush();
+  std::puts(line);
+  std::fflush(stdout);
   return 0;
 }
 
 int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
+  std::memset(controlWord, 0, sizeof(HAL_ControlWord));
   controlWord->enabled = SimDriverStationData->enabled;
   controlWord->autonomous = SimDriverStationData->autonomous;
   controlWord->test = SimDriverStationData->test;
@@ -179,9 +180,13 @@
   return name;
 }
 
-void HAL_FreeJoystickName(char* name) { std::free(name); }
+void HAL_FreeJoystickName(char* name) {
+  std::free(name);
+}
 
-int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) { return 0; }
+int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis) {
+  return 0;
+}
 
 int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
                                int32_t leftRumble, int32_t rightRumble) {
@@ -199,7 +204,9 @@
   return 0;
 }
 
-void HAL_ObserveUserProgramStarting(void) { HALSIM_SetProgramStarted(); }
+void HAL_ObserveUserProgramStarting(void) {
+  HALSIM_SetProgramStarted();
+}
 
 void HAL_ObserveUserProgramDisabled(void) {
   // TODO
@@ -230,12 +237,16 @@
   std::scoped_lock lock(newDSDataAvailableMutex);
   int& lastCount = GetThreadLocalLastCount();
   int currentCount = newDSDataAvailableCounter;
-  if (lastCount == currentCount) return false;
+  if (lastCount == currentCount) {
+    return false;
+  }
   lastCount = currentCount;
   return true;
 }
 
-void HAL_WaitForDSData(void) { HAL_WaitForDSDataTimeout(0); }
+void HAL_WaitForDSData(void) {
+  HAL_WaitForDSDataTimeout(0);
+}
 
 HAL_Bool HAL_WaitForDSDataTimeout(double timeout) {
   std::unique_lock lock(newDSDataAvailableMutex);
@@ -272,7 +283,9 @@
 static int32_t newDataOccur(uint32_t refNum) {
   // Since we could get other values, require our specific handle
   // to signal our threads
-  if (refNum != refNumber) return 0;
+  if (refNum != refNumber) {
+    return 0;
+  }
   SimDriverStationData->CallNewDataCallbacks();
   std::scoped_lock lock(newDSDataAvailableMutex);
   // Nofify all threads
@@ -286,11 +299,15 @@
   static std::atomic_bool initialized{false};
   static wpi::mutex initializeMutex;
   // Initial check, as if it's true initialization has finished
-  if (initialized) return;
+  if (initialized) {
+    return;
+  }
 
   std::scoped_lock lock(initializeMutex);
   // Second check in case another thread was waiting
-  if (initialized) return;
+  if (initialized) {
+    return;
+  }
 
   SimDriverStationData->ResetData();
 
@@ -302,6 +319,8 @@
   initialized = true;
 }
 
-void HAL_ReleaseDSMutex(void) { newDataOccur(refNumber); }
+void HAL_ReleaseDSMutex(void) {
+  newDataOccur(refNumber);
+}
 
 }  // extern "C"
diff --git a/hal/src/main/native/sim/DutyCycle.cpp b/hal/src/main/native/sim/DutyCycle.cpp
index 0e14eeb..51c6506 100644
--- a/hal/src/main/native/sim/DutyCycle.cpp
+++ b/hal/src/main/native/sim/DutyCycle.cpp
@@ -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.
 
 #include "hal/DutyCycle.h"
 
@@ -26,16 +23,14 @@
 static LimitedHandleResource<HAL_DutyCycleHandle, DutyCycle, kNumDutyCycles,
                              HAL_HandleEnum::DutyCycle>* dutyCycleHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDutyCycle() {
   static LimitedHandleResource<HAL_DutyCycleHandle, DutyCycle, kNumDutyCycles,
                                HAL_HandleEnum::DutyCycle>
       dcH;
   dutyCycleHandles = &dcH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_Handle digitalSourceHandle,
@@ -65,14 +60,18 @@
 void HAL_FreeDutyCycle(HAL_DutyCycleHandle dutyCycleHandle) {
   auto dutyCycle = dutyCycleHandles->Get(dutyCycleHandle);
   dutyCycleHandles->Free(dutyCycleHandle);
-  if (dutyCycle == nullptr) return;
+  if (dutyCycle == nullptr) {
+    return;
+  }
   SimDutyCycleData[dutyCycle->index].initialized = false;
 }
 
 void HAL_SetDutyCycleSimDevice(HAL_EncoderHandle handle,
                                HAL_SimDeviceHandle device) {
   auto dutyCycle = dutyCycleHandles->Get(handle);
-  if (dutyCycle == nullptr) return;
+  if (dutyCycle == nullptr) {
+    return;
+  }
   SimDutyCycleData[dutyCycle->index].simDevice = device;
 }
 
diff --git a/hal/src/main/native/sim/Encoder.cpp b/hal/src/main/native/sim/Encoder.cpp
index 32416f0..78aa281 100644
--- a/hal/src/main/native/sim/Encoder.cpp
+++ b/hal/src/main/native/sim/Encoder.cpp
@@ -1,14 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/Encoder.h"
 
 #include "CounterInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/Errors.h"
 #include "hal/handles/HandlesInternal.h"
@@ -20,6 +18,8 @@
 namespace {
 struct Encoder {
   HAL_Handle nativeHandle;
+  HAL_FPGAEncoderHandle fpgaHandle;
+  HAL_CounterHandle counterHandle;
   HAL_EncoderEncodingType encodingType;
   double distancePerPulse;
   uint8_t index;
@@ -34,8 +34,7 @@
 static LimitedHandleResource<HAL_FPGAEncoderHandle, Empty, kNumEncoders,
                              HAL_HandleEnum::FPGAEncoder>* fpgaEncoderHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeEncoder() {
   static LimitedHandleResource<HAL_FPGAEncoderHandle, Empty, kNumEncoders,
                                HAL_HandleEnum::FPGAEncoder>
@@ -47,7 +46,21 @@
       eH;
   encoderHandles = &eH;
 }
-}  // namespace init
+}  // namespace hal::init
+
+namespace hal {
+bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
+                          HAL_FPGAEncoderHandle* fpgaHandle,
+                          HAL_CounterHandle* counterHandle) {
+  auto encoder = encoderHandles->Get(handle);
+  if (!handle) {
+    return false;
+  }
+
+  *fpgaHandle = encoder->fpgaHandle;
+  *counterHandle = encoder->counterHandle;
+  return true;
+}
 }  // namespace hal
 
 extern "C" {
@@ -90,13 +103,22 @@
   encoder->nativeHandle = nativeHandle;
   encoder->encodingType = encodingType;
   encoder->distancePerPulse = 1.0;
+  if (encodingType == HAL_EncoderEncodingType::HAL_Encoder_k4X) {
+    encoder->fpgaHandle = nativeHandle;
+    encoder->counterHandle = HAL_kInvalidHandle;
+  } else {
+    encoder->fpgaHandle = HAL_kInvalidHandle;
+    encoder->counterHandle = nativeHandle;
+  }
   return handle;
 }
 
 void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status) {
   auto encoder = encoderHandles->Get(encoderHandle);
   encoderHandles->Free(encoderHandle);
-  if (encoder == nullptr) return;
+  if (encoder == nullptr) {
+    return;
+  }
   if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::FPGAEncoder)) {
     fpgaEncoderHandles->Free(encoder->nativeHandle);
   } else if (isHandleType(encoder->nativeHandle, HAL_HandleEnum::Counter)) {
@@ -108,7 +130,9 @@
 void HAL_SetEncoderSimDevice(HAL_EncoderHandle handle,
                              HAL_SimDeviceHandle device) {
   auto encoder = encoderHandles->Get(handle);
-  if (encoder == nullptr) return;
+  if (encoder == nullptr) {
+    return;
+  }
   SimEncoderData[encoder->index].simDevice = device;
 }
 
@@ -174,9 +198,9 @@
     return;
   }
 
+  SimEncoderData[encoder->index].reset = true;
   SimEncoderData[encoder->index].count = 0;
   SimEncoderData[encoder->index].period = std::numeric_limits<double>::max();
-  SimEncoderData[encoder->index].reset = true;
 }
 double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status) {
   auto encoder = encoderHandles->Get(encoderHandle);
@@ -247,6 +271,7 @@
 
   if (minRate == 0.0) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, "minRate must not be 0");
     return;
   }
 
@@ -263,6 +288,7 @@
 
   if (distancePerPulse == 0.0) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, "distancePerPulse must not be 0");
     return;
   }
   encoder->distancePerPulse = distancePerPulse;
diff --git a/hal/src/main/native/sim/ErrorsInternal.h b/hal/src/main/native/sim/ErrorsInternal.h
index 55372d8..42d1560 100644
--- a/hal/src/main/native/sim/ErrorsInternal.h
+++ b/hal/src/main/native/sim/ErrorsInternal.h
@@ -1,13 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* 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
 
-typedef enum {
+#include <stdint.h>
+
+enum CTR_Code {
   CTR_OKAY,       // No Error - Function executed as expected
   CTR_RxTimeout,  // CAN frame has not been received within specified period of
                   // time.
@@ -18,7 +17,7 @@
   CTR_SigNotUpdated,      // Have not received an value response for signal.
   CTR_BufferFull,  // Caller attempted to insert data into a buffer that is
                    // full.
-} CTR_Code;
+};
 
 // VISA Error
 #define _VI_ERROR (-2147483647L - 1)
@@ -109,104 +108,104 @@
  * Represents the resulting status of a function call through its return value.
  * 0 is success, negative values are errors, and positive values are warnings.
  */
-typedef int32_t NiFpga_Status;
+using NiFpga_Status = int32_t;  // NOLINT
 
 /**
  * No errors or warnings.
  */
-static const NiFpga_Status NiFpga_Status_Success = 0;
+constexpr NiFpga_Status NiFpga_Status_Success = 0;
 
 /**
  * The timeout expired before the FIFO operation could complete.
  */
-static const NiFpga_Status NiFpga_Status_FifoTimeout = -50400;
+constexpr NiFpga_Status NiFpga_Status_FifoTimeout = -50400;
 
 /**
  * No transfer is in progress because the transfer was aborted by the client.
  * The operation could not be completed as specified.
  */
-static const NiFpga_Status NiFpga_Status_TransferAborted = -50405;
+constexpr NiFpga_Status NiFpga_Status_TransferAborted = -50405;
 
 /**
  * A memory allocation failed. Try again after rebooting.
  */
-static const NiFpga_Status NiFpga_Status_MemoryFull = -52000;
+constexpr NiFpga_Status NiFpga_Status_MemoryFull = -52000;
 
 /**
  * An unexpected software error occurred.
  */
-static const NiFpga_Status NiFpga_Status_SoftwareFault = -52003;
+constexpr NiFpga_Status NiFpga_Status_SoftwareFault = -52003;
 
 /**
  * A parameter to a function was not valid. This could be a NULL pointer, a bad
  * value, etc.
  */
-static const NiFpga_Status NiFpga_Status_InvalidParameter = -52005;
+constexpr NiFpga_Status NiFpga_Status_InvalidParameter = -52005;
 
 /**
  * A required resource was not found. The NiFpga.* library, the RIO resource, or
  * some other resource may be missing.
  */
-static const NiFpga_Status NiFpga_Status_ResourceNotFound = -52006;
+constexpr NiFpga_Status NiFpga_Status_ResourceNotFound = -52006;
 
 /**
  * A required resource was not properly initialized. This could occur if
  * NiFpga_Initialize was not called or a required NiFpga_IrqContext was not
  * reserved.
  */
-static const NiFpga_Status NiFpga_Status_ResourceNotInitialized = -52010;
+constexpr NiFpga_Status NiFpga_Status_ResourceNotInitialized = -52010;
 
 /**
  * A hardware failure has occurred. The operation could not be completed as
  * specified.
  */
-static const NiFpga_Status NiFpga_Status_HardwareFault = -52018;
+constexpr NiFpga_Status NiFpga_Status_HardwareFault = -52018;
 
 /**
  * The FPGA is already running.
  */
-static const NiFpga_Status NiFpga_Status_FpgaAlreadyRunning = -61003;
+constexpr NiFpga_Status NiFpga_Status_FpgaAlreadyRunning = -61003;
 
 /**
  * An error occurred downloading the VI to the FPGA device. Verify that
  * the target is connected and powered and that the resource of the target
  * is properly configured.
  */
-static const NiFpga_Status NiFpga_Status_DownloadError = -61018;
+constexpr NiFpga_Status NiFpga_Status_DownloadError = -61018;
 
 /**
  * The bitfile was not compiled for the specified resource's device type.
  */
-static const NiFpga_Status NiFpga_Status_DeviceTypeMismatch = -61024;
+constexpr NiFpga_Status NiFpga_Status_DeviceTypeMismatch = -61024;
 
 /**
  * An error was detected in the communication between the host computer and the
  * FPGA target.
  */
-static const NiFpga_Status NiFpga_Status_CommunicationTimeout = -61046;
+constexpr NiFpga_Status NiFpga_Status_CommunicationTimeout = -61046;
 
 /**
  * The timeout expired before any of the IRQs were asserted.
  */
-static const NiFpga_Status NiFpga_Status_IrqTimeout = -61060;
+constexpr NiFpga_Status NiFpga_Status_IrqTimeout = -61060;
 
 /**
  * The specified bitfile is invalid or corrupt.
  */
-static const NiFpga_Status NiFpga_Status_CorruptBitfile = -61070;
+constexpr NiFpga_Status NiFpga_Status_CorruptBitfile = -61070;
 
 /**
  * The requested FIFO depth is invalid. It is either 0 or an amount not
  * supported by the hardware.
  */
-static const NiFpga_Status NiFpga_Status_BadDepth = -61072;
+constexpr NiFpga_Status NiFpga_Status_BadDepth = -61072;
 
 /**
  * The number of FIFO elements is invalid. Either the number is greater than the
  * depth of the host memory DMA FIFO, or more elements were requested for
  * release than had been acquired.
  */
-static const NiFpga_Status NiFpga_Status_BadReadWriteCount = -61073;
+constexpr NiFpga_Status NiFpga_Status_BadReadWriteCount = -61073;
 
 /**
  * A hardware clocking error occurred. A derived clock lost lock with its base
@@ -219,62 +218,62 @@
  * generated from free-running, on-board sources, please contact National
  * Instruments technical support at ni.com/support.
  */
-static const NiFpga_Status NiFpga_Status_ClockLostLock = -61083;
+constexpr NiFpga_Status NiFpga_Status_ClockLostLock = -61083;
 
 /**
  * The operation could not be performed because the FPGA is busy. Stop all
  * activities on the FPGA before requesting this operation. If the target is in
  * Scan Interface programming mode, put it in FPGA Interface programming mode.
  */
-static const NiFpga_Status NiFpga_Status_FpgaBusy = -61141;
+constexpr NiFpga_Status NiFpga_Status_FpgaBusy = -61141;
 
 /**
  * The operation could not be performed because the FPGA is busy operating in
  * FPGA Interface C API mode. Stop all activities on the FPGA before requesting
  * this operation.
  */
-static const NiFpga_Status NiFpga_Status_FpgaBusyFpgaInterfaceCApi = -61200;
+constexpr NiFpga_Status NiFpga_Status_FpgaBusyFpgaInterfaceCApi = -61200;
 
 /**
  * The chassis is in Scan Interface programming mode. In order to run FPGA VIs,
  * you must go to the chassis properties page, select FPGA programming mode, and
  * deploy settings.
  */
-static const NiFpga_Status NiFpga_Status_FpgaBusyScanInterface = -61201;
+constexpr NiFpga_Status NiFpga_Status_FpgaBusyScanInterface = -61201;
 
 /**
  * The operation could not be performed because the FPGA is busy operating in
  * FPGA Interface mode. Stop all activities on the FPGA before requesting this
  * operation.
  */
-static const NiFpga_Status NiFpga_Status_FpgaBusyFpgaInterface = -61202;
+constexpr NiFpga_Status NiFpga_Status_FpgaBusyFpgaInterface = -61202;
 
 /**
  * The operation could not be performed because the FPGA is busy operating in
  * Interactive mode. Stop all activities on the FPGA before requesting this
  * operation.
  */
-static const NiFpga_Status NiFpga_Status_FpgaBusyInteractive = -61203;
+constexpr NiFpga_Status NiFpga_Status_FpgaBusyInteractive = -61203;
 
 /**
  * The operation could not be performed because the FPGA is busy operating in
  * Emulation mode. Stop all activities on the FPGA before requesting this
  * operation.
  */
-static const NiFpga_Status NiFpga_Status_FpgaBusyEmulation = -61204;
+constexpr NiFpga_Status NiFpga_Status_FpgaBusyEmulation = -61204;
 
 /**
  * LabVIEW FPGA does not support the Reset method for bitfiles that allow
  * removal of implicit enable signals in single-cycle Timed Loops.
  */
-static const NiFpga_Status NiFpga_Status_ResetCalledWithImplicitEnableRemoval =
+constexpr NiFpga_Status NiFpga_Status_ResetCalledWithImplicitEnableRemoval =
     -61211;
 
 /**
  * LabVIEW FPGA does not support the Abort method for bitfiles that allow
  * removal of implicit enable signals in single-cycle Timed Loops.
  */
-static const NiFpga_Status NiFpga_Status_AbortCalledWithImplicitEnableRemoval =
+constexpr NiFpga_Status NiFpga_Status_AbortCalledWithImplicitEnableRemoval =
     -61212;
 
 /**
@@ -283,7 +282,7 @@
  * Pass the NiFpga_CloseAttribute_NoResetIfLastSession attribute to NiFpga_Close
  * instead of 0.
  */
-static const NiFpga_Status
+constexpr NiFpga_Status
     NiFpga_Status_CloseAndResetCalledWithImplicitEnableRemoval = -61213;
 
 /**
@@ -291,14 +290,14 @@
  * Timed Loops, LabVIEW FPGA does not support this method prior to running the
  * bitfile.
  */
-static const NiFpga_Status NiFpga_Status_ImplicitEnableRemovalButNotYetRun =
+constexpr NiFpga_Status NiFpga_Status_ImplicitEnableRemovalButNotYetRun =
     -61214;
 
 /**
  * Bitfiles that allow removal of implicit enable signals in single-cycle Timed
  * Loops can run only once. Download the bitfile again before re-running the VI.
  */
-static const NiFpga_Status
+constexpr NiFpga_Status
     NiFpga_Status_RunAfterStoppedCalledWithImplicitEnableRemoval = -61215;
 
 /**
@@ -307,8 +306,7 @@
  * protocol. If you are generating your clocks internally, please contact
  * National Instruments Technical Support.
  */
-static const NiFpga_Status NiFpga_Status_GatedClockHandshakingViolation =
-    -61216;
+constexpr NiFpga_Status NiFpga_Status_GatedClockHandshakingViolation = -61216;
 
 /**
  * The number of elements requested must be less than or equal to the number of
@@ -316,7 +314,7 @@
  * fewer unacquired elements left in the FIFO than are being requested. Release
  * some acquired elements before acquiring more elements.
  */
-static const NiFpga_Status NiFpga_Status_ElementsNotPermissibleToBeAcquired =
+constexpr NiFpga_Status NiFpga_Status_ElementsNotPermissibleToBeAcquired =
     -61219;
 
 /**
@@ -324,12 +322,12 @@
  * discovery mode. Wait for configuration or discovery to complete and retry
  * your operation.
  */
-static const NiFpga_Status NiFpga_Status_FpgaBusyConfiguration = -61252;
+constexpr NiFpga_Status NiFpga_Status_FpgaBusyConfiguration = -61252;
 
 /**
  * An unexpected internal error occurred.
  */
-static const NiFpga_Status NiFpga_Status_InternalError = -61499;
+constexpr NiFpga_Status NiFpga_Status_InternalError = -61499;
 
 /**
  * The NI-RIO driver was unable to allocate memory for a FIFO. This can happen
@@ -338,52 +336,52 @@
  * to reconfigure the controller with a greater maximum FIFO depth. For more
  * information, refer to the NI KnowledgeBase article 65OF2ERQ.
  */
-static const NiFpga_Status NiFpga_Status_TotalDmaFifoDepthExceeded = -63003;
+constexpr NiFpga_Status NiFpga_Status_TotalDmaFifoDepthExceeded = -63003;
 
 /**
  * Access to the remote system was denied. Use MAX to check the Remote Device
  * Access settings under Software>>NI-RIO>>NI-RIO Settings on the remote system.
  */
-static const NiFpga_Status NiFpga_Status_AccessDenied = -63033;
+constexpr NiFpga_Status NiFpga_Status_AccessDenied = -63033;
 
 /**
  * The NI-RIO software on the host is not compatible with the software on the
  * target. Upgrade the NI-RIO software on the host in order to connect to this
  * target.
  */
-static const NiFpga_Status NiFpga_Status_HostVersionMismatch = -63038;
+constexpr NiFpga_Status NiFpga_Status_HostVersionMismatch = -63038;
 
 /**
  * A connection could not be established to the specified remote device. Ensure
  * that the device is on and accessible over the network, that NI-RIO software
  * is installed, and that the RIO server is running and properly configured.
  */
-static const NiFpga_Status NiFpga_Status_RpcConnectionError = -63040;
+constexpr NiFpga_Status NiFpga_Status_RpcConnectionError = -63040;
 
 /**
  * The RPC session is invalid. The target may have reset or been rebooted. Check
  * the network connection and retry the operation.
  */
-static const NiFpga_Status NiFpga_Status_RpcSessionError = -63043;
+constexpr NiFpga_Status NiFpga_Status_RpcSessionError = -63043;
 
 /**
  * The operation could not complete because another session is accessing the
  * FIFO. Close the other session and retry.
  */
-static const NiFpga_Status NiFpga_Status_FifoReserved = -63082;
+constexpr NiFpga_Status NiFpga_Status_FifoReserved = -63082;
 
 /**
  * A Configure FIFO, Stop FIFO, Read FIFO, or Write FIFO function was called
  * while the host had acquired elements of the FIFO. Release all acquired
  * elements before configuring, stopping, reading, or writing.
  */
-static const NiFpga_Status NiFpga_Status_FifoElementsCurrentlyAcquired = -63083;
+constexpr NiFpga_Status NiFpga_Status_FifoElementsCurrentlyAcquired = -63083;
 
 /**
  * A function was called using a misaligned address. The address must be a
  * multiple of the size of the datatype.
  */
-static const NiFpga_Status NiFpga_Status_MisalignedAccess = -63084;
+constexpr NiFpga_Status NiFpga_Status_MisalignedAccess = -63084;
 
 /**
  * The FPGA Read/Write Control Function is accessing a control or indicator
@@ -391,7 +389,7 @@
  * Refer to the hardware documentation for the limitations on data types for
  * this target.
  */
-static const NiFpga_Status NiFpga_Status_ControlOrIndicatorTooLarge = -63085;
+constexpr NiFpga_Status NiFpga_Status_ControlOrIndicatorTooLarge = -63085;
 
 /**
  * A valid .lvbitx bitfile is required. If you are using a valid .lvbitx
@@ -399,14 +397,14 @@
  * Determine which version of LabVIEW was used to make the bitfile, update your
  * software to that version or later, and try again.
  */
-static const NiFpga_Status NiFpga_Status_BitfileReadError = -63101;
+constexpr NiFpga_Status NiFpga_Status_BitfileReadError = -63101;
 
 /**
  * The specified signature does not match the signature of the bitfile. If the
  * bitfile has been recompiled, regenerate the C API and rebuild the
  * application.
  */
-static const NiFpga_Status NiFpga_Status_SignatureMismatch = -63106;
+constexpr NiFpga_Status NiFpga_Status_SignatureMismatch = -63106;
 
 /**
  * The bitfile you are trying to use is incompatible with the version
@@ -416,33 +414,33 @@
  * with the same version of NI-RIO that is currently installed on the
  * target and/or host.
  */
-static const NiFpga_Status NiFpga_Status_IncompatibleBitfile = -63107;
+constexpr NiFpga_Status NiFpga_Status_IncompatibleBitfile = -63107;
 
 /**
  * Either the supplied resource name is invalid as a RIO resource name, or the
  * device was not found. Use MAX to find the proper resource name for the
  * intended device.
  */
-static const NiFpga_Status NiFpga_Status_InvalidResourceName = -63192;
+constexpr NiFpga_Status NiFpga_Status_InvalidResourceName = -63192;
 
 /**
  * The requested feature is not supported.
  */
-static const NiFpga_Status NiFpga_Status_FeatureNotSupported = -63193;
+constexpr NiFpga_Status NiFpga_Status_FeatureNotSupported = -63193;
 
 /**
  * The NI-RIO software on the target system is not compatible with this
  * software. Upgrade the NI-RIO software on the target system.
  */
-static const NiFpga_Status NiFpga_Status_VersionMismatch = -63194;
+constexpr NiFpga_Status NiFpga_Status_VersionMismatch = -63194;
 
 /**
  * The session is invalid or has been closed.
  */
-static const NiFpga_Status NiFpga_Status_InvalidSession = -63195;
+constexpr NiFpga_Status NiFpga_Status_InvalidSession = -63195;
 
 /**
  * The maximum number of open FPGA sessions has been reached. Close some open
  * sessions.
  */
-static const NiFpga_Status NiFpga_Status_OutOfHandles = -63198;
+constexpr NiFpga_Status NiFpga_Status_OutOfHandles = -63198;
diff --git a/hal/src/main/native/sim/Extensions.cpp b/hal/src/main/native/sim/Extensions.cpp
index e638d6a..9131bcb 100644
--- a/hal/src/main/native/sim/Extensions.cpp
+++ b/hal/src/main/native/sim/Extensions.cpp
@@ -1,18 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/Extensions.h"
 
+#include <cstdio>
+#include <string_view>
 #include <vector>
 
-#include <wpi/Path.h>
-#include <wpi/SmallString.h>
-#include <wpi/StringRef.h>
-#include <wpi/raw_ostream.h>
+#include <fmt/format.h>
+#include <wpi/SmallVector.h>
+#include <wpi/StringExtras.h>
+#include <wpi/fs.h>
 #include <wpi/spinlock.h>
 
 #if defined(WIN32) || defined(_WIN32)
@@ -27,7 +26,7 @@
 #define DLOPEN(a) LoadLibraryA(a)
 #define DLSYM GetProcAddress
 #define DLCLOSE FreeLibrary
-#define DLERROR "error #" << GetLastError()
+#define DLERROR fmt::format("error #{}", GetLastError())
 #else
 #define DELIM ':'
 #define HTYPE void*
@@ -43,11 +42,9 @@
 static std::vector<std::pair<void*, void (*)(void*, const char*, void*)>>
     gExtensionListeners;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeExtensions() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 static bool& GetShowNotFoundMessage() {
   static bool showMsg = true;
@@ -58,66 +55,64 @@
 
 int HAL_LoadOneExtension(const char* library) {
   int rc = 1;  // It is expected and reasonable not to find an extra simulation
-  wpi::outs() << "HAL Extensions: Attempting to load: "
-              << wpi::sys::path::stem(library) << "\n";
-  wpi::outs().flush();
+  fmt::print("HAL Extensions: Attempting to load: {}\n",
+             fs::path{library}.stem().string());
+  std::fflush(stdout);
   HTYPE handle = DLOPEN(library);
 #if !defined(WIN32) && !defined(_WIN32)
   if (!handle) {
-    wpi::SmallString<128> libraryName("lib");
-    libraryName += library;
 #if defined(__APPLE__)
-    libraryName += ".dylib";
+    auto libraryName = fmt::format("lib{}.dylib", library);
 #else
-    libraryName += ".so";
+    auto libraryName = fmt::format("lib{}.so", library);
 #endif
-    wpi::outs() << "HAL Extensions: Load failed: " << DLERROR
-                << "\nTrying modified name: "
-                << wpi::sys::path::stem(libraryName) << "\n";
-    wpi::outs().flush();
+    fmt::print("HAL Extensions: Load failed: {}\nTrying modified name: {}\n",
+               DLERROR, fs::path{libraryName}.stem().string());
+    std::fflush(stdout);
     handle = DLOPEN(libraryName.c_str());
   }
 #endif
   if (!handle) {
-    wpi::outs() << "HAL Extensions: Failed to load library: " << DLERROR
-                << '\n';
-    wpi::outs().flush();
+    fmt::print("HAL Extensions: Failed to load library: {}\n", DLERROR);
+    std::fflush(stdout);
     return rc;
   }
 
   auto init = reinterpret_cast<halsim_extension_init_func_t*>(
       DLSYM(handle, "HALSIM_InitExtension"));
 
-  if (init) rc = (*init)();
+  if (init) {
+    rc = (*init)();
+  }
 
   if (rc != 0) {
-    wpi::outs() << "HAL Extensions: Failed to load extension\n";
-    wpi::outs().flush();
+    std::puts("HAL Extensions: Failed to load extension");
+    std::fflush(stdout);
     DLCLOSE(handle);
   } else {
-    wpi::outs() << "HAL Extensions: Successfully loaded extension\n";
-    wpi::outs().flush();
+    std::puts("HAL Extensions: Successfully loaded extension");
+    std::fflush(stdout);
   }
   return rc;
 }
 
 int HAL_LoadExtensions(void) {
   int rc = 1;
-  wpi::SmallVector<wpi::StringRef, 2> libraries;
+  wpi::SmallVector<std::string_view, 2> libraries;
   const char* e = std::getenv("HALSIM_EXTENSIONS");
   if (!e) {
     if (GetShowNotFoundMessage()) {
-      wpi::outs() << "HAL Extensions: No extensions found\n";
-      wpi::outs().flush();
+      std::puts("HAL Extensions: No extensions found");
+      std::fflush(stdout);
     }
     return rc;
   }
-  wpi::StringRef env{e};
-  env.split(libraries, DELIM, -1, false);
-  for (auto& libref : libraries) {
-    wpi::SmallString<128> library(libref);
-    rc = HAL_LoadOneExtension(library.c_str());
-    if (rc < 0) break;
+  wpi::split(e, libraries, DELIM, -1, false);
+  for (auto& library : libraries) {
+    rc = HAL_LoadOneExtension(std::string(library).c_str());
+    if (rc < 0) {
+      break;
+    }
   }
   return rc;
 }
@@ -125,8 +120,9 @@
 void HAL_RegisterExtension(const char* name, void* data) {
   std::scoped_lock lock(gExtensionRegistryMutex);
   gExtensionRegistry.emplace_back(name, data);
-  for (auto&& listener : gExtensionListeners)
+  for (auto&& listener : gExtensionListeners) {
     listener.second(listener.first, name, data);
+  }
 }
 
 void HAL_RegisterExtensionListener(void* param,
@@ -134,8 +130,9 @@
                                                 void* data)) {
   std::scoped_lock lock(gExtensionRegistryMutex);
   gExtensionListeners.emplace_back(param, func);
-  for (auto&& extension : gExtensionRegistry)
+  for (auto&& extension : gExtensionRegistry) {
     func(param, extension.first, extension.second);
+  }
 }
 
 void HAL_SetShowExtensionsNotFoundMessages(HAL_Bool showMessage) {
diff --git a/hal/src/main/native/sim/HAL.cpp b/hal/src/main/native/sim/HAL.cpp
index 64c4a10..8d911df 100644
--- a/hal/src/main/native/sim/HAL.cpp
+++ b/hal/src/main/native/sim/HAL.cpp
@@ -1,16 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/HAL.h"
 
+#include <cstdio>
 #include <vector>
 
 #include <wpi/mutex.h>
-#include <wpi/raw_ostream.h>
 #include <wpi/spinlock.h>
 
 #ifdef _WIN32
@@ -26,16 +23,41 @@
 #include "hal/Extensions.h"
 #include "hal/handles/HandlesInternal.h"
 #include "hal/simulation/DriverStationData.h"
+#include "hal/simulation/SimCallbackRegistry.h"
 #include "mockdata/RoboRioDataInternal.h"
 
 using namespace hal;
 
-static HAL_RuntimeType runtimeType{HAL_Mock};
+namespace {
+class SimPeriodicCallbackRegistry : public impl::SimCallbackRegistryBase {
+ public:
+  int32_t Register(HALSIM_SimPeriodicCallback callback, void* param) {
+    std::scoped_lock lock(m_mutex);
+    return DoRegister(reinterpret_cast<RawFunctor>(callback), param);
+  }
+
+  void operator()() const {
+#ifdef _MSC_VER  // work around VS2019 16.4.0 bug
+    std::scoped_lock<wpi::recursive_spinlock> lock(m_mutex);
+#else
+    std::scoped_lock lock(m_mutex);
+#endif
+    if (m_callbacks) {
+      for (auto&& cb : *m_callbacks) {
+        reinterpret_cast<HALSIM_SimPeriodicCallback>(cb.callback)(cb.param);
+      }
+    }
+  }
+};
+}  // namespace
+
+static HAL_RuntimeType runtimeType{HAL_Runtime_Simulation};
 static wpi::spinlock gOnShutdownMutex;
 static std::vector<std::pair<void*, void (*)(void*)>> gOnShutdown;
+static SimPeriodicCallbackRegistry gSimPeriodicBefore;
+static SimPeriodicCallbackRegistry gSimPeriodicAfter;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeHAL() {
   InitializeAccelerometerData();
   InitializeAddressableLEDData();
@@ -51,8 +73,9 @@
   InitializeDriverStationData();
   InitializeEncoderData();
   InitializeI2CData();
-  InitializePCMData();
-  InitializePDPData();
+  InitializeCTREPCMData();
+  InitializeREVPHData();
+  InitializePowerDistributionData();
   InitializePWMData();
   InitializeRelayData();
   InitializeRoboRioData();
@@ -68,7 +91,6 @@
   InitializeAnalogOutput();
   InitializeAnalogTrigger();
   InitializeCAN();
-  InitializeCompressor();
   InitializeConstants();
   InitializeCounter();
   InitializeDigitalInternal();
@@ -82,32 +104,38 @@
   InitializeMain();
   InitializeMockHooks();
   InitializeNotifier();
-  InitializePDP();
+  InitializePowerDistribution();
   InitializePorts();
   InitializePower();
+  InitializeCTREPCM();
+  InitializeREVPH();
   InitializePWM();
   InitializeRelay();
   InitializeSerialPort();
   InitializeSimDevice();
-  InitializeSolenoid();
   InitializeSPI();
   InitializeThreads();
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
 HAL_PortHandle HAL_GetPort(int32_t channel) {
   // Dont allow a number that wouldn't fit in a uint8_t
-  if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
+  if (channel < 0 || channel >= 255) {
+    return HAL_kInvalidHandle;
+  }
   return createPortHandle(channel, 1);
 }
 
 HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
   // Dont allow a number that wouldn't fit in a uint8_t
-  if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
-  if (module < 0 || module >= 255) return HAL_kInvalidHandle;
+  if (channel < 0 || channel >= 255) {
+    return HAL_kInvalidHandle;
+  }
+  if (module < 0 || module >= 255) {
+    return HAL_kInvalidHandle;
+  }
   return createPortHandle(channel, module);
 }
 
@@ -223,14 +251,22 @@
       return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
     case HAL_LED_CHANNEL_ERROR:
       return HAL_LED_CHANNEL_ERROR_MESSAGE;
+    case HAL_USE_LAST_ERROR:
+      return HAL_USE_LAST_ERROR_MESSAGE;
+    case HAL_CONSOLE_OUT_ENABLED_ERROR:
+      return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
     default:
       return "Unknown error status";
   }
 }
 
-HAL_RuntimeType HAL_GetRuntimeType(void) { return runtimeType; }
+HAL_RuntimeType HAL_GetRuntimeType(void) {
+  return runtimeType;
+}
 
-void HALSIM_SetRuntimeType(HAL_RuntimeType type) { runtimeType = type; }
+void HALSIM_SetRuntimeType(HAL_RuntimeType type) {
+  runtimeType = type;
+}
 
 int32_t HAL_GetFPGAVersion(int32_t* status) {
   return 2018;  // Automatically script this at some point
@@ -240,28 +276,32 @@
   return 0;  // TODO: Find a better number to return;
 }
 
-uint64_t HAL_GetFPGATime(int32_t* status) { return hal::GetFPGATime(); }
+uint64_t HAL_GetFPGATime(int32_t* status) {
+  return hal::GetFPGATime();
+}
 
-uint64_t HAL_ExpandFPGATime(uint32_t unexpanded_lower, int32_t* status) {
+uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
   // Capture the current FPGA time.  This will give us the upper half of the
   // clock.
-  uint64_t fpga_time = HAL_GetFPGATime(status);
-  if (*status != 0) return 0;
+  uint64_t fpgaTime = HAL_GetFPGATime(status);
+  if (*status != 0) {
+    return 0;
+  }
 
   // Now, we need to detect the case where the lower bits rolled over after we
   // sampled.  In that case, the upper bits will be 1 bigger than they should
   // be.
 
   // Break it into lower and upper portions.
-  uint32_t lower = fpga_time & 0xffffffffull;
-  uint64_t upper = (fpga_time >> 32) & 0xffffffff;
+  uint32_t lower = fpgaTime & 0xffffffffull;
+  uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
 
   // The time was sampled *before* the current time, so roll it back.
-  if (lower < unexpanded_lower) {
+  if (lower < unexpandedLower) {
     --upper;
   }
 
-  return (upper << 32) + static_cast<uint64_t>(unexpanded_lower);
+  return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
 }
 
 HAL_Bool HAL_GetFPGAButton(int32_t* status) {
@@ -280,11 +320,15 @@
   static std::atomic_bool initialized{false};
   static wpi::mutex initializeMutex;
   // Initial check, as if it's true initialization has finished
-  if (initialized) return true;
+  if (initialized) {
+    return true;
+  }
 
   std::scoped_lock lock(initializeMutex);
   // Second check in case another thread was waiting
-  if (initialized) return true;
+  if (initialized) {
+    return true;
+  }
 
   hal::init::InitializeHAL();
 
@@ -311,8 +355,14 @@
   }
 #endif  // _WIN32
 
-  wpi::outs().SetUnbuffered();
-  if (HAL_LoadExtensions() < 0) return false;
+#ifndef _WIN32
+  setlinebuf(stdin);
+  setlinebuf(stdout);
+#endif
+
+  if (HAL_LoadExtensions() < 0) {
+    return false;
+  }
 
   return true;  // Add initialization if we need to at a later point
 }
@@ -333,6 +383,32 @@
   gOnShutdown.emplace_back(param, func);
 }
 
+void HAL_SimPeriodicBefore(void) {
+  gSimPeriodicBefore();
+}
+
+void HAL_SimPeriodicAfter(void) {
+  gSimPeriodicAfter();
+}
+
+int32_t HALSIM_RegisterSimPeriodicBeforeCallback(
+    HALSIM_SimPeriodicCallback callback, void* param) {
+  return gSimPeriodicBefore.Register(callback, param);
+}
+
+void HALSIM_CancelSimPeriodicBeforeCallback(int32_t uid) {
+  gSimPeriodicBefore.Cancel(uid);
+}
+
+int32_t HALSIM_RegisterSimPeriodicAfterCallback(
+    HALSIM_SimPeriodicCallback callback, void* param) {
+  return gSimPeriodicAfter.Register(callback, param);
+}
+
+void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid) {
+  gSimPeriodicAfter.Cancel(uid);
+}
+
 int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
                    const char* feature) {
   return 0;  // Do nothing for now
diff --git a/hal/src/main/native/sim/HALInitializer.cpp b/hal/src/main/native/sim/HALInitializer.cpp
index 5c2242b..50cc9ab 100644
--- a/hal/src/main/native/sim/HALInitializer.cpp
+++ b/hal/src/main/native/sim/HALInitializer.cpp
@@ -1,17 +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.
 
 #include "HALInitializer.h"
 
 #include "hal/HALBase.h"
 
-namespace hal {
-namespace init {
+namespace hal::init {
 std::atomic_bool HAL_IsInitialized{false};
-void RunInitialize() { HAL_Initialize(500, 0); }
-}  // namespace init
-}  // namespace hal
+void RunInitialize() {
+  HAL_Initialize(500, 0);
+}
+}  // namespace hal::init
diff --git a/hal/src/main/native/sim/HALInitializer.h b/hal/src/main/native/sim/HALInitializer.h
index 29efac5..308e2f4 100644
--- a/hal/src/main/native/sim/HALInitializer.h
+++ b/hal/src/main/native/sim/HALInitializer.h
@@ -1,20 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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 <atomic>
 
-namespace hal {
-namespace init {
+namespace hal::init {
 extern std::atomic_bool HAL_IsInitialized;
 extern void RunInitialize();
-static inline void CheckInit() {
-  if (HAL_IsInitialized.load(std::memory_order_relaxed)) return;
+inline void CheckInit() {
+  if (HAL_IsInitialized.load(std::memory_order_relaxed)) {
+    return;
+  }
   RunInitialize();
 }
 
@@ -33,8 +31,9 @@
 extern void InitializeDriverStationData();
 extern void InitializeEncoderData();
 extern void InitializeI2CData();
-extern void InitializePCMData();
-extern void InitializePDPData();
+extern void InitializeCTREPCMData();
+extern void InitializeREVPHData();
+extern void InitializePowerDistributionData();
 extern void InitializePWMData();
 extern void InitializeRelayData();
 extern void InitializeRoboRioData();
@@ -50,7 +49,6 @@
 extern void InitializeAnalogOutput();
 extern void InitializeAnalogTrigger();
 extern void InitializeCAN();
-extern void InitializeCompressor();
 extern void InitializeConstants();
 extern void InitializeCounter();
 extern void InitializeDigitalInternal();
@@ -64,16 +62,16 @@
 extern void InitializeMain();
 extern void InitializeMockHooks();
 extern void InitializeNotifier();
-extern void InitializePDP();
+extern void InitializePowerDistribution();
 extern void InitializePorts();
 extern void InitializePower();
+extern void InitializeCTREPCM();
+extern void InitializeREVPH();
 extern void InitializePWM();
 extern void InitializeRelay();
 extern void InitializeSerialPort();
 extern void InitializeSimDevice();
-extern void InitializeSolenoid();
 extern void InitializeSPI();
 extern void InitializeThreads();
 
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
diff --git a/hal/src/main/native/sim/HALInternal.h b/hal/src/main/native/sim/HALInternal.h
new file mode 100644
index 0000000..7a7863a
--- /dev/null
+++ b/hal/src/main/native/sim/HALInternal.h
@@ -0,0 +1,19 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <string_view>
+
+namespace hal {
+void SetLastError(int32_t* status, std::string_view value);
+void SetLastErrorIndexOutOfRange(int32_t* status, std::string_view message,
+                                 int32_t minimum, int32_t maximum,
+                                 int32_t channel);
+void SetLastErrorPreviouslyAllocated(int32_t* status, std::string_view message,
+                                     int32_t channel,
+                                     std::string_view previousAllocation);
+}  // namespace hal
diff --git a/hal/src/main/native/sim/I2C.cpp b/hal/src/main/native/sim/I2C.cpp
index fe4952f..0b50fe6 100644
--- a/hal/src/main/native/sim/I2C.cpp
+++ b/hal/src/main/native/sim/I2C.cpp
@@ -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.
 
 #include "hal/I2C.h"
 
@@ -12,11 +9,9 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeI2C() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status) {
@@ -40,5 +35,7 @@
   SimI2CData[port].Read(deviceAddress, buffer, count);
   return 0;
 }
-void HAL_CloseI2C(HAL_I2CPort port) { SimI2CData[port].initialized = false; }
+void HAL_CloseI2C(HAL_I2CPort port) {
+  SimI2CData[port].initialized = false;
+}
 }  // extern "C"
diff --git a/hal/src/main/native/sim/Interrupts.cpp b/hal/src/main/native/sim/Interrupts.cpp
index 7760f06..e55316d 100644
--- a/hal/src/main/native/sim/Interrupts.cpp
+++ b/hal/src/main/native/sim/Interrupts.cpp
@@ -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.
 
 #include "hal/Interrupts.h"
 
@@ -45,16 +42,12 @@
   HAL_Handle portHandle;
   uint8_t index;
   HAL_AnalogTriggerType trigType;
-  bool watcher;
   int64_t risingTimestamp;
   int64_t fallingTimestamp;
   bool previousState;
   bool fireOnUp;
   bool fireOnDown;
   int32_t callbackId;
-
-  void* callbackParam;
-  HAL_InterruptHandlerFunction callbackFunction;
 };
 
 struct SynchronousWaitData {
@@ -67,13 +60,12 @@
 static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
                              HAL_HandleEnum::Interrupt>* interruptHandles;
 
-typedef HAL_Handle SynchronousWaitDataHandle;
+using SynchronousWaitDataHandle = HAL_Handle;
 static UnlimitedHandleResource<SynchronousWaitDataHandle, SynchronousWaitData,
                                HAL_HandleEnum::Vendor>*
     synchronousInterruptHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeInterrupts() {
   static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
                                HAL_HandleEnum::Interrupt>
@@ -84,12 +76,10 @@
       siH;
   synchronousInterruptHandles = &siH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
-HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
-                                             int32_t* status) {
+HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) {
   hal::init::CheckInit();
   HAL_InterruptHandle handle = interruptHandles->Allocate();
   if (handle == HAL_kInvalidHandle) {
@@ -105,19 +95,10 @@
   anInterrupt->index = getHandleIndex(handle);
   anInterrupt->callbackId = -1;
 
-  anInterrupt->watcher = watcher;
-
   return handle;
 }
-void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
-                          int32_t* status) {
-  HAL_DisableInterrupts(interruptHandle, status);
-  auto anInterrupt = interruptHandles->Get(interruptHandle);
+void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {
   interruptHandles->Free(interruptHandle);
-  if (anInterrupt == nullptr) {
-    return nullptr;
-  }
-  return anInterrupt->callbackParam;
 }
 
 static void ProcessInterruptDigitalSynchronous(const char* name, void* param,
@@ -128,18 +109,32 @@
   SynchronousWaitDataHandle handle =
       static_cast<SynchronousWaitDataHandle>(handleTmp);
   auto interruptData = synchronousInterruptHandles->Get(handle);
-  if (interruptData == nullptr) return;
+  if (interruptData == nullptr) {
+    return;
+  }
   auto interrupt = interruptHandles->Get(interruptData->interruptHandle);
-  if (interrupt == nullptr) return;
+  if (interrupt == nullptr) {
+    return;
+  }
   // Have a valid interrupt
-  if (value->type != HAL_Type::HAL_BOOLEAN) return;
+  if (value->type != HAL_Type::HAL_BOOLEAN) {
+    return;
+  }
   bool retVal = value->data.v_boolean;
+  auto previousState = interrupt->previousState;
+  interrupt->previousState = retVal;
   // If no change in interrupt, return;
-  if (retVal == interrupt->previousState) return;
+  if (retVal == previousState) {
+    return;
+  }
   // If its a falling change, and we dont fire on falling return
-  if (interrupt->previousState && !interrupt->fireOnDown) return;
+  if (previousState && !interrupt->fireOnDown) {
+    return;
+  }
   // If its a rising change, and we dont fire on rising return.
-  if (!interrupt->previousState && !interrupt->fireOnUp) return;
+  if (!previousState && !interrupt->fireOnUp) {
+    return;
+  }
 
   interruptData->waitPredicate = true;
 
@@ -161,11 +156,17 @@
   SynchronousWaitDataHandle handle =
       static_cast<SynchronousWaitDataHandle>(handleTmp);
   auto interruptData = synchronousInterruptHandles->Get(handle);
-  if (interruptData == nullptr) return;
+  if (interruptData == nullptr) {
+    return;
+  }
   auto interrupt = interruptHandles->Get(interruptData->interruptHandle);
-  if (interrupt == nullptr) return;
+  if (interrupt == nullptr) {
+    return;
+  }
   // Have a valid interrupt
-  if (value->type != HAL_Type::HAL_DOUBLE) return;
+  if (value->type != HAL_Type::HAL_DOUBLE) {
+    return;
+  }
   int32_t status = 0;
   bool retVal = GetAnalogTriggerValue(interrupt->portHandle,
                                       interrupt->trigType, &status);
@@ -175,12 +176,20 @@
     // Pulse interrupt
     interruptData->waitCond.notify_all();
   }
+  auto previousState = interrupt->previousState;
+  interrupt->previousState = retVal;
   // If no change in interrupt, return;
-  if (retVal == interrupt->previousState) return;
+  if (retVal == previousState) {
+    return;
+  }
   // If its a falling change, and we dont fire on falling return
-  if (interrupt->previousState && !interrupt->fireOnDown) return;
+  if (previousState && !interrupt->fireOnDown) {
+    return;
+  }
   // If its a rising change, and we dont fire on rising return.
-  if (!interrupt->previousState && !interrupt->fireOnUp) return;
+  if (!previousState && !interrupt->fireOnUp) {
+    return;
+  }
 
   interruptData->waitPredicate = true;
 
@@ -207,7 +216,9 @@
 
   int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
 
-  if (status != 0) return WaitResult::Timeout;
+  if (status != 0) {
+    return WaitResult::Timeout;
+  }
 
   interrupt->previousState = SimDIOData[digitalIndex].value;
 
@@ -238,7 +249,9 @@
   (void)synchronousInterruptHandles->Free(dataHandle);
 
   // Check for what to return
-  if (timedOut) return WaitResult::Timeout;
+  if (timedOut) {
+    return WaitResult::Timeout;
+  }
   // True => false, Falling
   if (interrupt->previousState) {
     // Set our return value and our timestamps
@@ -268,12 +281,16 @@
   interrupt->previousState = GetAnalogTriggerValue(
       interrupt->portHandle, interrupt->trigType, &status);
 
-  if (status != 0) return WaitResult::Timeout;
+  if (status != 0) {
+    return WaitResult::Timeout;
+  }
 
   int32_t analogIndex =
       GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
 
-  if (status != 0) return WaitResult::Timeout;
+  if (status != 0) {
+    return WaitResult::Timeout;
+  }
 
   int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
       &ProcessInterruptAnalogSynchronous,
@@ -302,7 +319,9 @@
   (void)synchronousInterruptHandles->Free(dataHandle);
 
   // Check for what to return
-  if (timedOut) return WaitResult::Timeout;
+  if (timedOut) {
+    return WaitResult::Timeout;
+  }
   // True => false, Falling
   if (interrupt->previousState) {
     // Set our return value and our timestamps
@@ -323,12 +342,6 @@
     return WaitResult::Timeout;
   }
 
-  // Check to make sure we are actually an interrupt in synchronous mode
-  if (!interrupt->watcher) {
-    *status = NiFpga_Status_InvalidParameter;
-    return WaitResult::Timeout;
-  }
-
   if (interrupt->isAnalog) {
     return WaitForInterruptAnalog(interruptHandle, interrupt.get(), timeout,
                                   ignorePrevious);
@@ -338,158 +351,6 @@
   }
 }
 
-static void ProcessInterruptDigitalAsynchronous(const char* name, void* param,
-                                                const struct HAL_Value* value) {
-  // void* is a HAL handle
-  // convert to uintptr_t first, then to handle
-  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
-  HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
-  auto interrupt = interruptHandles->Get(handle);
-  if (interrupt == nullptr) return;
-  // Have a valid interrupt
-  if (value->type != HAL_Type::HAL_BOOLEAN) return;
-  bool retVal = value->data.v_boolean;
-  // If no change in interrupt, return;
-  if (retVal == interrupt->previousState) return;
-  int32_t mask = 0;
-  if (interrupt->previousState) {
-    interrupt->previousState = retVal;
-    interrupt->fallingTimestamp = hal::GetFPGATime();
-    mask = 1 << (8 + interrupt->index);
-    if (!interrupt->fireOnDown) return;
-  } else {
-    interrupt->previousState = retVal;
-    interrupt->risingTimestamp = hal::GetFPGATime();
-    mask = 1 << (interrupt->index);
-    if (!interrupt->fireOnUp) return;
-  }
-
-  // run callback
-  auto callback = interrupt->callbackFunction;
-  if (callback == nullptr) return;
-  callback(mask, interrupt->callbackParam);
-}
-
-static void ProcessInterruptAnalogAsynchronous(const char* name, void* param,
-                                               const struct HAL_Value* value) {
-  // void* is a HAL handle
-  // convert to intptr_t first, then to handle
-  uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
-  HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
-  auto interrupt = interruptHandles->Get(handle);
-  if (interrupt == nullptr) return;
-  // Have a valid interrupt
-  if (value->type != HAL_Type::HAL_DOUBLE) return;
-  int32_t status = 0;
-  bool retVal = GetAnalogTriggerValue(interrupt->portHandle,
-                                      interrupt->trigType, &status);
-  if (status != 0) return;
-  // If no change in interrupt, return;
-  if (retVal == interrupt->previousState) return;
-  int mask = 0;
-  if (interrupt->previousState) {
-    interrupt->previousState = retVal;
-    interrupt->fallingTimestamp = hal::GetFPGATime();
-    if (!interrupt->fireOnDown) return;
-    mask = 1 << (8 + interrupt->index);
-  } else {
-    interrupt->previousState = retVal;
-    interrupt->risingTimestamp = hal::GetFPGATime();
-    if (!interrupt->fireOnUp) return;
-    mask = 1 << (interrupt->index);
-  }
-
-  // run callback
-  auto callback = interrupt->callbackFunction;
-  if (callback == nullptr) return;
-  callback(mask, interrupt->callbackParam);
-}
-
-static void EnableInterruptsDigital(HAL_InterruptHandle handle,
-                                    Interrupt* interrupt) {
-  int32_t status = 0;
-  int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
-  if (status != 0) return;
-
-  interrupt->previousState = SimDIOData[digitalIndex].value;
-
-  int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback(
-      &ProcessInterruptDigitalAsynchronous,
-      reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
-  interrupt->callbackId = uid;
-}
-
-static void EnableInterruptsAnalog(HAL_InterruptHandle handle,
-                                   Interrupt* interrupt) {
-  int32_t status = 0;
-  int32_t analogIndex =
-      GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
-  if (status != 0) return;
-
-  status = 0;
-  interrupt->previousState = GetAnalogTriggerValue(
-      interrupt->portHandle, interrupt->trigType, &status);
-  if (status != 0) return;
-
-  int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
-      &ProcessInterruptAnalogAsynchronous,
-      reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
-  interrupt->callbackId = uid;
-}
-
-void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
-                          int32_t* status) {
-  auto interrupt = interruptHandles->Get(interruptHandle);
-  if (interrupt == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  // If we have not had a callback set, error out
-  if (interrupt->callbackFunction == nullptr) {
-    *status = INCOMPATIBLE_STATE;
-    return;
-  }
-
-  // EnableInterrupts has already been called
-  if (interrupt->callbackId >= 0) {
-    // We can double enable safely.
-    return;
-  }
-
-  if (interrupt->isAnalog) {
-    EnableInterruptsAnalog(interruptHandle, interrupt.get());
-  } else {
-    EnableInterruptsDigital(interruptHandle, interrupt.get());
-  }
-}
-void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
-                           int32_t* status) {
-  auto interrupt = interruptHandles->Get(interruptHandle);
-  if (interrupt == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  // No need to disable if we are already disabled
-  if (interrupt->callbackId < 0) return;
-
-  if (interrupt->isAnalog) {
-    // Do analog
-    int32_t status = 0;
-    int32_t analogIndex =
-        GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
-    if (status != 0) return;
-    SimAnalogInData[analogIndex].voltage.CancelCallback(interrupt->callbackId);
-  } else {
-    int32_t status = 0;
-    int32_t digitalIndex =
-        GetDigitalInputChannel(interrupt->portHandle, &status);
-    if (status != 0) return;
-    SimDIOData[digitalIndex].value.CancelCallback(interrupt->callbackId);
-  }
-  interrupt->callbackId = -1;
-}
 int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
                                          int32_t* status) {
   auto interrupt = interruptHandles->Get(interruptHandle);
@@ -535,24 +396,6 @@
   interrupt->trigType = analogTriggerType;
   interrupt->portHandle = digitalSourceHandle;
 }
-void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
-                                HAL_InterruptHandlerFunction handler,
-                                void* param, int32_t* status) {
-  auto interrupt = interruptHandles->Get(interruptHandle);
-  if (interrupt == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  interrupt->callbackFunction = handler;
-  interrupt->callbackParam = param;
-}
-
-void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
-                                        HAL_InterruptHandlerFunction handler,
-                                        void* param, int32_t* status) {
-  HAL_AttachInterruptHandler(interruptHandle, handler, param, status);
-}
 
 void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
                                   HAL_Bool risingEdge, HAL_Bool fallingEdge,
@@ -569,6 +412,19 @@
 
 void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
                                  int32_t* status) {
-  // Requires a fairly large rewrite to get working
+  auto interrupt = interruptHandles->Get(interruptHandle);
+  if (interrupt == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  synchronousInterruptHandles->ForEach(
+      [interruptHandle](SynchronousWaitDataHandle handle,
+                        SynchronousWaitData* data) {
+        if (data->interruptHandle == interruptHandle) {
+          data->waitPredicate = true;
+          data->waitCond.notify_all();
+        }
+      });
 }
 }  // extern "C"
diff --git a/hal/src/main/native/sim/MockHooks.cpp b/hal/src/main/native/sim/MockHooks.cpp
index 8fe387f..4e20c6a 100644
--- a/hal/src/main/native/sim/MockHooks.cpp
+++ b/hal/src/main/native/sim/MockHooks.cpp
@@ -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.
 
 #include <algorithm>
 #include <atomic>
@@ -11,6 +8,7 @@
 #include <cstdio>
 #include <thread>
 
+#include <fmt/format.h>
 #include <wpi/timestamp.h>
 
 #include "MockHooksInternal.h"
@@ -23,21 +21,25 @@
 static std::atomic<uint64_t> programPauseTime{0};
 static std::atomic<uint64_t> programStepTime{0};
 
-namespace hal {
-namespace init {
-void InitializeMockHooks() { wpi::SetNowImpl(GetFPGATime); }
-}  // namespace init
-}  // namespace hal
+namespace hal::init {
+void InitializeMockHooks() {
+  wpi::SetNowImpl(GetFPGATime);
+}
+}  // namespace hal::init
 
 namespace hal {
 void RestartTiming() {
   programStartTime = wpi::NowDefault();
   programStepTime = 0;
-  if (programPauseTime != 0) programPauseTime = programStartTime.load();
+  if (programPauseTime != 0) {
+    programPauseTime = programStartTime.load();
+  }
 }
 
 void PauseTiming() {
-  if (programPauseTime == 0) programPauseTime = wpi::NowDefault();
+  if (programPauseTime == 0) {
+    programPauseTime = wpi::NowDefault();
+  }
 }
 
 void ResumeTiming() {
@@ -47,20 +49,32 @@
   }
 }
 
-bool IsTimingPaused() { return programPauseTime != 0; }
+bool IsTimingPaused() {
+  return programPauseTime != 0;
+}
 
-void StepTiming(uint64_t delta) { programStepTime += delta; }
+void StepTiming(uint64_t delta) {
+  programStepTime += delta;
+}
 
 uint64_t GetFPGATime() {
   uint64_t curTime = programPauseTime;
-  if (curTime == 0) curTime = wpi::NowDefault();
+  if (curTime == 0) {
+    curTime = wpi::NowDefault();
+  }
   return curTime + programStepTime - programStartTime;
 }
 
-double GetFPGATimestamp() { return GetFPGATime() * 1.0e-6; }
+double GetFPGATimestamp() {
+  return GetFPGATime() * 1.0e-6;
+}
 
-void SetProgramStarted() { programStarted = true; }
-bool GetProgramStarted() { return programStarted; }
+void SetProgramStarted() {
+  programStarted = true;
+}
+bool GetProgramStarted() {
+  return programStarted;
+}
 }  // namespace hal
 
 using namespace hal;
@@ -70,16 +84,22 @@
   int count = 0;
   while (!programStarted) {
     count++;
-    std::printf("Waiting for program start signal: %d\n", count);
+    fmt::print("Waiting for program start signal: {}\n", count);
     std::this_thread::sleep_for(std::chrono::milliseconds(500));
   }
 }
 
-void HALSIM_SetProgramStarted(void) { SetProgramStarted(); }
+void HALSIM_SetProgramStarted(void) {
+  SetProgramStarted();
+}
 
-HAL_Bool HALSIM_GetProgramStarted(void) { return GetProgramStarted(); }
+HAL_Bool HALSIM_GetProgramStarted(void) {
+  return GetProgramStarted();
+}
 
-void HALSIM_RestartTiming(void) { RestartTiming(); }
+void HALSIM_RestartTiming(void) {
+  RestartTiming();
+}
 
 void HALSIM_PauseTiming(void) {
   PauseTiming();
@@ -91,7 +111,9 @@
   ResumeNotifiers();
 }
 
-HAL_Bool HALSIM_IsTimingPaused(void) { return IsTimingPaused(); }
+HAL_Bool HALSIM_IsTimingPaused(void) {
+  return IsTimingPaused();
+}
 
 void HALSIM_StepTiming(uint64_t delta) {
   WaitNotifiers();
diff --git a/hal/src/main/native/sim/MockHooksInternal.h b/hal/src/main/native/sim/MockHooksInternal.h
index c53f120..ace09da 100644
--- a/hal/src/main/native/sim/MockHooksInternal.h
+++ b/hal/src/main/native/sim/MockHooksInternal.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
 
diff --git a/hal/src/main/native/sim/Notifier.cpp b/hal/src/main/native/sim/Notifier.cpp
index a697275..49f1c80 100644
--- a/hal/src/main/native/sim/Notifier.cpp
+++ b/hal/src/main/native/sim/Notifier.cpp
@@ -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.
 
 #include "hal/Notifier.h"
 
@@ -71,7 +68,9 @@
 }
 }  // namespace init
 
-void PauseNotifiers() { notifiersPaused = true; }
+void PauseNotifiers() {
+  notifiersPaused = true;
+}
 
 void ResumeNotifiers() {
   notifiersPaused = false;
@@ -110,7 +109,9 @@
       // No longer need to wait for it, put at end so it can be erased
       std::swap(it, waiters[--end]);
     }
-    if (count == 0) break;
+    if (count == 0) {
+      break;
+    }
     waiters.resize(count);
     notifiersWaiterCond.wait_for(ulock, std::chrono::duration<double>(1));
   }
@@ -151,7 +152,9 @@
       // No longer need to wait for it, put at end so it can be erased
       it.swap(waiters[--end]);
     }
-    if (count == 0) break;
+    if (count == 0) {
+      break;
+    }
     waiters.resize(count);
     notifiersWaiterCond.wait_for(ulock, std::chrono::duration<double>(1));
   }
@@ -171,17 +174,26 @@
   return handle;
 }
 
+HAL_Bool HAL_SetNotifierThreadPriority(HAL_Bool realTime, int32_t priority,
+                                       int32_t* status) {
+  return true;
+}
+
 void HAL_SetNotifierName(HAL_NotifierHandle notifierHandle, const char* name,
                          int32_t* status) {
   auto notifier = notifierHandles->Get(notifierHandle);
-  if (!notifier) return;
+  if (!notifier) {
+    return;
+  }
   std::scoped_lock lock(notifier->mutex);
   notifier->name = name;
 }
 
 void HAL_StopNotifier(HAL_NotifierHandle notifierHandle, int32_t* status) {
   auto notifier = notifierHandles->Get(notifierHandle);
-  if (!notifier) return;
+  if (!notifier) {
+    return;
+  }
 
   {
     std::scoped_lock lock(notifier->mutex);
@@ -193,7 +205,9 @@
 
 void HAL_CleanNotifier(HAL_NotifierHandle notifierHandle, int32_t* status) {
   auto notifier = notifierHandles->Free(notifierHandle);
-  if (!notifier) return;
+  if (!notifier) {
+    return;
+  }
 
   // Just in case HAL_StopNotifier() wasn't called...
   {
@@ -207,7 +221,9 @@
 void HAL_UpdateNotifierAlarm(HAL_NotifierHandle notifierHandle,
                              uint64_t triggerTime, int32_t* status) {
   auto notifier = notifierHandles->Get(notifierHandle);
-  if (!notifier) return;
+  if (!notifier) {
+    return;
+  }
 
   {
     std::scoped_lock lock(notifier->mutex);
@@ -222,7 +238,9 @@
 void HAL_CancelNotifierAlarm(HAL_NotifierHandle notifierHandle,
                              int32_t* status) {
   auto notifier = notifierHandles->Get(notifierHandle);
-  if (!notifier) return;
+  if (!notifier) {
+    return;
+  }
 
   {
     std::scoped_lock lock(notifier->mutex);
@@ -233,7 +251,9 @@
 uint64_t HAL_WaitForNotifierAlarm(HAL_NotifierHandle notifierHandle,
                                   int32_t* status) {
   auto notifier = notifierHandles->Get(notifierHandle);
-  if (!notifier) return 0;
+  if (!notifier) {
+    return 0;
+  }
 
   std::unique_lock ulock(notifiersWaiterMutex);
   std::unique_lock lock(notifier->mutex);
@@ -268,8 +288,9 @@
   notifierHandles->ForEach([&](HAL_NotifierHandle, Notifier* notifier) {
     std::scoped_lock lock(notifier->mutex);
     if (notifier->active && notifier->waitTimeValid &&
-        timeout > notifier->waitTime)
+        timeout > notifier->waitTime) {
       timeout = notifier->waitTime;
+    }
   });
   return timeout;
 }
@@ -278,7 +299,9 @@
   int32_t count = 0;
   notifierHandles->ForEach([&](HAL_NotifierHandle, Notifier* notifier) {
     std::scoped_lock lock(notifier->mutex);
-    if (notifier->active) ++count;
+    if (notifier->active) {
+      ++count;
+    }
   });
   return count;
 }
@@ -287,7 +310,9 @@
   int32_t num = 0;
   notifierHandles->ForEach([&](HAL_NotifierHandle handle, Notifier* notifier) {
     std::scoped_lock lock(notifier->mutex);
-    if (!notifier->active) return;
+    if (!notifier->active) {
+      return;
+    }
     if (num < size) {
       arr[num].handle = handle;
       if (notifier->name.empty()) {
diff --git a/hal/src/main/native/sim/NotifierInternal.h b/hal/src/main/native/sim/NotifierInternal.h
index e6692ca..81d906e 100644
--- a/hal/src/main/native/sim/NotifierInternal.h
+++ b/hal/src/main/native/sim/NotifierInternal.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
 
diff --git a/hal/src/main/native/sim/PDP.cpp b/hal/src/main/native/sim/PDP.cpp
deleted file mode 100644
index cc095d0..0000000
--- a/hal/src/main/native/sim/PDP.cpp
+++ /dev/null
@@ -1,104 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "hal/PDP.h"
-
-#include "CANAPIInternal.h"
-#include "HALInitializer.h"
-#include "PortsInternal.h"
-#include "hal/CANAPI.h"
-#include "hal/Errors.h"
-#include "mockdata/PDPDataInternal.h"
-
-using namespace hal;
-
-static constexpr HAL_CANManufacturer manufacturer =
-    HAL_CANManufacturer::HAL_CAN_Man_kCTRE;
-
-static constexpr HAL_CANDeviceType deviceType =
-    HAL_CANDeviceType::HAL_CAN_Dev_kPowerDistribution;
-
-namespace hal {
-namespace init {
-void InitializePDP() {}
-}  // namespace init
-}  // namespace hal
-
-extern "C" {
-HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status) {
-  if (!HAL_CheckPDPModule(module)) {
-    *status = PARAMETER_OUT_OF_RANGE;
-    return HAL_kInvalidHandle;
-  }
-  hal::init::CheckInit();
-  SimPDPData[module].initialized = true;
-  auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
-
-  if (*status != 0) {
-    HAL_CleanCAN(handle);
-    return HAL_kInvalidHandle;
-  }
-
-  return handle;
-}
-
-HAL_Bool HAL_CheckPDPModule(int32_t module) {
-  return module < kNumPDPModules && module >= 0;
-}
-
-HAL_Bool HAL_CheckPDPChannel(int32_t channel) {
-  return channel < kNumPDPChannels && channel >= 0;
-}
-
-void HAL_CleanPDP(HAL_PDPHandle handle) { HAL_CleanCAN(handle); }
-
-double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
-  auto module = hal::can::GetCANModuleFromHandle(handle, status);
-  if (*status != 0) {
-    return 0.0;
-  }
-  return SimPDPData[module].temperature;
-}
-double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
-  auto module = hal::can::GetCANModuleFromHandle(handle, status);
-  if (*status != 0) {
-    return 0.0;
-  }
-  return SimPDPData[module].voltage;
-}
-double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
-                                int32_t* status) {
-  auto module = hal::can::GetCANModuleFromHandle(handle, status);
-  if (*status != 0) {
-    return 0.0;
-  }
-  return SimPDPData[module].current[channel];
-}
-void HAL_GetPDPAllChannelCurrents(HAL_PDPHandle handle, double* currents,
-                                  int32_t* status) {
-  auto module = hal::can::GetCANModuleFromHandle(handle, status);
-  if (*status != 0) {
-    return;
-  }
-
-  auto& data = SimPDPData[module];
-  for (int i = 0; i < kNumPDPChannels; i++) {
-    currents[i] = data.current[i];
-  }
-}
-double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
-  return 0.0;
-}
-double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
-  return 0.0;
-}
-double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
-  return 0.0;
-}
-void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {}
-void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {}
-}  // extern "C"
diff --git a/hal/src/main/native/sim/PWM.cpp b/hal/src/main/native/sim/PWM.cpp
index 228b540..698769f 100644
--- a/hal/src/main/native/sim/PWM.cpp
+++ b/hal/src/main/native/sim/PWM.cpp
@@ -1,37 +1,35 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/PWM.h"
 
 #include "ConstantsInternal.h"
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/handles/HandlesInternal.h"
 #include "mockdata/PWMDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializePWM() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
 HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
+                                        const char* allocationLocation,
                                         int32_t* status) {
   hal::init::CheckInit();
-  if (*status != 0) return HAL_kInvalidHandle;
 
   int16_t channel = getPortHandleChannel(portHandle);
   if (channel == InvalidHandleIndex) {
-    *status = PARAMETER_OUT_OF_RANGE;
+    *status = RESOURCE_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
+                                     kNumPWMChannels, channel);
     return HAL_kInvalidHandle;
   }
 
@@ -43,16 +41,20 @@
     channel = remapMXPPWMChannel(channel) + 10;  // remap MXP to proper channel
   }
 
-  auto handle =
-      digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM, status);
+  HAL_DigitalHandle handle;
 
-  if (*status != 0)
+  auto port = digitalChannelHandles->Allocate(channel, HAL_HandleEnum::PWM,
+                                              &handle, status);
+
+  if (*status != 0) {
+    if (port) {
+      hal::SetLastErrorPreviouslyAllocated(status, "PWM or DIO", channel,
+                                           port->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
+                                       kNumPWMChannels, channel);
+    }
     return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
-
-  auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::PWM);
-  if (port == nullptr) {  // would only occur on thread issue.
-    *status = HAL_HANDLE_ERROR;
-    return HAL_kInvalidHandle;
   }
 
   port->channel = origChannel;
@@ -62,6 +64,8 @@
   // Defaults to allow an always valid config.
   HAL_SetPWMConfig(handle, 2.0, 1.501, 1.5, 1.499, 1.0, status);
 
+  port->previousAllocation = allocationLocation ? allocationLocation : "";
+
   return handle;
 }
 void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status) {
@@ -92,7 +96,9 @@
   // calculate the loop time in milliseconds
   double loopTime =
       HAL_GetPWMLoopTiming(status) / (kSystemClockTicksPerMicrosecond * 1e3);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
 
   int32_t maxPwm = static_cast<int32_t>((max - kDefaultPwmCenter) / loopTime +
                                         kDefaultPwmStepsDown - 1);
@@ -252,8 +258,12 @@
   }
 
   double speed = SimPWMData[port->channel].speed;
-  if (speed > 1) speed = 1;
-  if (speed < -1) speed = -1;
+  if (speed > 1) {
+    speed = 1;
+  }
+  if (speed < -1) {
+    speed = -1;
+  }
   return speed;
 }
 
@@ -269,8 +279,12 @@
   }
 
   double position = SimPWMData[port->channel].position;
-  if (position > 1) position = 1;
-  if (position < 0) position = 0;
+  if (position > 1) {
+    position = 1;
+  }
+  if (position < 0) {
+    position = 0;
+  }
   return position;
 }
 
@@ -296,7 +310,11 @@
   SimPWMData[port->channel].periodScale = squelchMask;
 }
 
-int32_t HAL_GetPWMLoopTiming(int32_t* status) { return kExpectedLoopTiming; }
+int32_t HAL_GetPWMLoopTiming(int32_t* status) {
+  return kExpectedLoopTiming;
+}
 
-uint64_t HAL_GetPWMCycleStartTime(int32_t* status) { return 0; }
+uint64_t HAL_GetPWMCycleStartTime(int32_t* status) {
+  return 0;
+}
 }  // extern "C"
diff --git a/hal/src/main/native/sim/Ports.cpp b/hal/src/main/native/sim/Ports.cpp
index 2f670b3..08ca975 100644
--- a/hal/src/main/native/sim/Ports.cpp
+++ b/hal/src/main/native/sim/Ports.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "hal/Ports.h"
 
@@ -11,31 +8,81 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializePorts() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
-int32_t HAL_GetNumAccumulators(void) { return kNumAccumulators; }
-int32_t HAL_GetNumAnalogTriggers(void) { return kNumAnalogTriggers; }
-int32_t HAL_GetNumAnalogInputs(void) { return kNumAnalogInputs; }
-int32_t HAL_GetNumAnalogOutputs(void) { return kNumAnalogOutputs; }
-int32_t HAL_GetNumCounters(void) { return kNumCounters; }
-int32_t HAL_GetNumDigitalHeaders(void) { return kNumDigitalHeaders; }
-int32_t HAL_GetNumPWMHeaders(void) { return kNumPWMHeaders; }
-int32_t HAL_GetNumDigitalChannels(void) { return kNumDigitalChannels; }
-int32_t HAL_GetNumPWMChannels(void) { return kNumPWMChannels; }
-int32_t HAL_GetNumDigitalPWMOutputs(void) { return kNumDigitalPWMOutputs; }
-int32_t HAL_GetNumEncoders(void) { return kNumEncoders; }
-int32_t HAL_GetNumInterrupts(void) { return kNumInterrupts; }
-int32_t HAL_GetNumRelayChannels(void) { return kNumRelayChannels; }
-int32_t HAL_GetNumRelayHeaders(void) { return kNumRelayHeaders; }
-int32_t HAL_GetNumPCMModules(void) { return kNumPCMModules; }
-int32_t HAL_GetNumSolenoidChannels(void) { return kNumSolenoidChannels; }
-int32_t HAL_GetNumPDPModules(void) { return kNumPDPModules; }
-int32_t HAL_GetNumPDPChannels(void) { return kNumPDPChannels; }
-int32_t HAL_GetNumDutyCycles(void) { return kNumDutyCycles; }
-int32_t HAL_GetNumAddressableLEDs(void) { return kNumAddressableLEDs; }
+int32_t HAL_GetNumAccumulators(void) {
+  return kNumAccumulators;
+}
+int32_t HAL_GetNumAnalogTriggers(void) {
+  return kNumAnalogTriggers;
+}
+int32_t HAL_GetNumAnalogInputs(void) {
+  return kNumAnalogInputs;
+}
+int32_t HAL_GetNumAnalogOutputs(void) {
+  return kNumAnalogOutputs;
+}
+int32_t HAL_GetNumCounters(void) {
+  return kNumCounters;
+}
+int32_t HAL_GetNumDigitalHeaders(void) {
+  return kNumDigitalHeaders;
+}
+int32_t HAL_GetNumPWMHeaders(void) {
+  return kNumPWMHeaders;
+}
+int32_t HAL_GetNumDigitalChannels(void) {
+  return kNumDigitalChannels;
+}
+int32_t HAL_GetNumPWMChannels(void) {
+  return kNumPWMChannels;
+}
+int32_t HAL_GetNumDigitalPWMOutputs(void) {
+  return kNumDigitalPWMOutputs;
+}
+int32_t HAL_GetNumEncoders(void) {
+  return kNumEncoders;
+}
+int32_t HAL_GetNumInterrupts(void) {
+  return kNumInterrupts;
+}
+int32_t HAL_GetNumRelayChannels(void) {
+  return kNumRelayChannels;
+}
+int32_t HAL_GetNumRelayHeaders(void) {
+  return kNumRelayHeaders;
+}
+int32_t HAL_GetNumCTREPCMModules(void) {
+  return kNumCTREPCMModules;
+}
+int32_t HAL_GetNumCTRESolenoidChannels(void) {
+  return kNumCTRESolenoidChannels;
+}
+int32_t HAL_GetNumCTREPDPModules(void) {
+  return kNumCTREPDPModules;
+}
+int32_t HAL_GetNumCTREPDPChannels(void) {
+  return kNumCTREPDPChannels;
+}
+int32_t HAL_GetNumREVPDHModules(void) {
+  return kNumREVPDHModules;
+}
+int32_t HAL_GetNumREVPDHChannels(void) {
+  return kNumREVPDHChannels;
+}
+int32_t HAL_GetNumREVPHModules(void) {
+  return kNumREVPHModules;
+}
+int32_t HAL_GetNumREVPHChannels(void) {
+  return kNumREVPHChannels;
+}
+int32_t HAL_GetNumDutyCycles(void) {
+  return kNumDutyCycles;
+}
+int32_t HAL_GetNumAddressableLEDs(void) {
+  return kNumAddressableLEDs;
+}
 }  // extern "C"
diff --git a/hal/src/main/native/sim/PortsInternal.h b/hal/src/main/native/sim/PortsInternal.h
index d143aca..2d1a205 100644
--- a/hal/src/main/native/sim/PortsInternal.h
+++ b/hal/src/main/native/sim/PortsInternal.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
 
@@ -24,10 +21,14 @@
 constexpr int32_t kNumInterrupts = 8;
 constexpr int32_t kNumRelayChannels = 8;
 constexpr int32_t kNumRelayHeaders = kNumRelayChannels / 2;
-constexpr int32_t kNumPCMModules = 63;
-constexpr int32_t kNumSolenoidChannels = 8;
-constexpr int32_t kNumPDPModules = 63;
-constexpr int32_t kNumPDPChannels = 16;
+constexpr int32_t kNumCTREPCMModules = 63;
+constexpr int32_t kNumCTRESolenoidChannels = 8;
+constexpr int32_t kNumCTREPDPModules = 63;
+constexpr int32_t kNumCTREPDPChannels = 16;
+constexpr int32_t kNumREVPDHModules = 63;
+constexpr int32_t kNumREVPDHChannels = 24;
 constexpr int32_t kNumDutyCycles = 8;
 constexpr int32_t kNumAddressableLEDs = 1;
+constexpr int32_t kNumREVPHModules = 63;
+constexpr int32_t kNumREVPHChannels = 16;
 }  // namespace hal
diff --git a/hal/src/main/native/sim/Power.cpp b/hal/src/main/native/sim/Power.cpp
index e8ce710..08d5638 100644
--- a/hal/src/main/native/sim/Power.cpp
+++ b/hal/src/main/native/sim/Power.cpp
@@ -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.
 
 #include "hal/Power.h"
 
@@ -11,16 +8,18 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializePower() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 // TODO: Fix the naming in here
 extern "C" {
-double HAL_GetVinVoltage(int32_t* status) { return SimRoboRioData->vInVoltage; }
-double HAL_GetVinCurrent(int32_t* status) { return SimRoboRioData->vInCurrent; }
+double HAL_GetVinVoltage(int32_t* status) {
+  return SimRoboRioData->vInVoltage;
+}
+double HAL_GetVinCurrent(int32_t* status) {
+  return SimRoboRioData->vInCurrent;
+}
 double HAL_GetUserVoltage6V(int32_t* status) {
   return SimRoboRioData->userVoltage6V;
 }
@@ -57,4 +56,10 @@
 int32_t HAL_GetUserCurrentFaults3V3(int32_t* status) {
   return SimRoboRioData->userFaults3V3;
 }
+void HAL_SetBrownoutVoltage(double voltage, int32_t* status) {
+  SimRoboRioData->brownoutVoltage = voltage;
+}
+double HAL_GetBrownoutVoltage(int32_t* status) {
+  return SimRoboRioData->brownoutVoltage;
+}
 }  // extern "C"
diff --git a/hal/src/main/native/sim/PowerDistribution.cpp b/hal/src/main/native/sim/PowerDistribution.cpp
new file mode 100644
index 0000000..85646cf
--- /dev/null
+++ b/hal/src/main/native/sim/PowerDistribution.cpp
@@ -0,0 +1,158 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "hal/PowerDistribution.h"
+
+#include <fmt/format.h>
+
+#include "CANAPIInternal.h"
+#include "HALInitializer.h"
+#include "HALInternal.h"
+#include "PortsInternal.h"
+#include "hal/CANAPI.h"
+#include "hal/Errors.h"
+#include "mockdata/PowerDistributionDataInternal.h"
+
+using namespace hal;
+
+static constexpr HAL_CANManufacturer manufacturer =
+    HAL_CANManufacturer::HAL_CAN_Man_kCTRE;
+
+static constexpr HAL_CANDeviceType deviceType =
+    HAL_CANDeviceType::HAL_CAN_Dev_kPowerDistribution;
+
+namespace hal::init {
+void InitializePowerDistribution() {}
+}  // namespace hal::init
+
+extern "C" {
+HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
+    int32_t module, HAL_PowerDistributionType type,
+    const char* allocationLocation, int32_t* status) {
+  if (!HAL_CheckPowerDistributionModule(module, type)) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, fmt::format("Invalid pdp module {}", module));
+    return HAL_kInvalidHandle;
+  }
+  hal::init::CheckInit();
+  SimPowerDistributionData[module].initialized = true;
+  auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
+
+  if (*status != 0) {
+    HAL_CleanCAN(handle);
+    return HAL_kInvalidHandle;
+  }
+
+  return handle;
+}
+
+int32_t HAL_GetPowerDistributionModuleNumber(HAL_PowerDistributionHandle handle,
+                                             int32_t* status) {
+  auto module = hal::can::GetCANModuleFromHandle(handle, status);
+  if (*status != 0) {
+    return 0;
+  }
+  return module;
+}
+
+HAL_Bool HAL_CheckPowerDistributionModule(int32_t module,
+                                          HAL_PowerDistributionType type) {
+  if (type == HAL_PowerDistributionType::HAL_PowerDistributionType_kCTRE) {
+    return module < kNumCTREPDPModules && module >= 0;
+  } else {
+    return module < kNumREVPDHModules && module >= 1;
+  }
+}
+
+HAL_Bool HAL_CheckPowerDistributionChannel(HAL_PowerDistributionHandle handle,
+                                           int32_t channel) {
+  // TODO make this grab from the handle directly
+  if (false) {
+    return channel < kNumCTREPDPChannels && channel >= 0;
+  } else {
+    return channel < kNumREVPDHChannels && channel >= 0;
+  }
+}
+
+HAL_PowerDistributionType HAL_GetPowerDistributionType(
+    HAL_PowerDistributionHandle handle, int32_t* status) {
+  return HAL_PowerDistributionType::HAL_PowerDistributionType_kCTRE;
+}
+
+int32_t HAL_GetPowerDistributionNumChannels(HAL_PowerDistributionHandle handle,
+                                            int32_t* status) {
+  // TODO make this grab from the handle directly
+  if (false) {
+    return kNumCTREPDPChannels;
+  } else {
+    return kNumREVPDHChannels;
+  }
+}
+
+void HAL_CleanPowerDistribution(HAL_PowerDistributionHandle handle) {
+  HAL_CleanCAN(handle);
+}
+
+double HAL_GetPowerDistributionTemperature(HAL_PowerDistributionHandle handle,
+                                           int32_t* status) {
+  auto module = hal::can::GetCANModuleFromHandle(handle, status);
+  if (*status != 0) {
+    return 0.0;
+  }
+  return SimPowerDistributionData[module].temperature;
+}
+double HAL_GetPowerDistributionVoltage(HAL_PowerDistributionHandle handle,
+                                       int32_t* status) {
+  auto module = hal::can::GetCANModuleFromHandle(handle, status);
+  if (*status != 0) {
+    return 0.0;
+  }
+  return SimPowerDistributionData[module].voltage;
+}
+double HAL_GetPowerDistributionChannelCurrent(
+    HAL_PowerDistributionHandle handle, int32_t channel, int32_t* status) {
+  auto module = hal::can::GetCANModuleFromHandle(handle, status);
+  if (*status != 0) {
+    return 0.0;
+  }
+  return SimPowerDistributionData[module].current[channel];
+}
+void HAL_GetPowerDistributionAllChannelCurrents(
+    HAL_PowerDistributionHandle handle, double* currents,
+    int32_t currentsLength, int32_t* status) {
+  auto module = hal::can::GetCANModuleFromHandle(handle, status);
+  if (*status != 0) {
+    return;
+  }
+
+  auto& data = SimPowerDistributionData[module];
+  int toCopy = (std::min)(currentsLength, kNumPDSimChannels);
+  for (int i = 0; i < toCopy; i++) {
+    currents[i] = data.current[i];
+  }
+}
+double HAL_GetPowerDistributionTotalCurrent(HAL_PowerDistributionHandle handle,
+                                            int32_t* status) {
+  return 0.0;
+}
+double HAL_GetPowerDistributionTotalPower(HAL_PowerDistributionHandle handle,
+                                          int32_t* status) {
+  return 0.0;
+}
+double HAL_GetPowerDistributionTotalEnergy(HAL_PowerDistributionHandle handle,
+                                           int32_t* status) {
+  return 0.0;
+}
+void HAL_ResetPowerDistributionTotalEnergy(HAL_PowerDistributionHandle handle,
+                                           int32_t* status) {}
+void HAL_ClearPowerDistributionStickyFaults(HAL_PowerDistributionHandle handle,
+                                            int32_t* status) {}
+void HAL_SetPowerDistributionSwitchableChannel(
+    HAL_PowerDistributionHandle handle, HAL_Bool state, int32_t* status) {}
+
+HAL_Bool HAL_GetPowerDistributionSwitchableChannel(
+    HAL_PowerDistributionHandle handle, int32_t* status) {
+  return false;
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/REVPH.cpp b/hal/src/main/native/sim/REVPH.cpp
new file mode 100644
index 0000000..9ddb655
--- /dev/null
+++ b/hal/src/main/native/sim/REVPH.cpp
@@ -0,0 +1,181 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "hal/REVPH.h"
+
+#include "HALInitializer.h"
+#include "HALInternal.h"
+#include "PortsInternal.h"
+#include "hal/CANAPI.h"
+#include "hal/Errors.h"
+#include "hal/handles/IndexedHandleResource.h"
+#include "mockdata/REVPHDataInternal.h"
+
+using namespace hal;
+
+namespace {
+struct PCM {
+  int32_t module;
+  wpi::mutex lock;
+  std::string previousAllocation;
+};
+}  // namespace
+
+static IndexedHandleResource<HAL_REVPHHandle, PCM, kNumREVPHModules,
+                             HAL_HandleEnum::REVPH>* pcmHandles;
+
+namespace hal::init {
+void InitializeREVPH() {
+  static IndexedHandleResource<HAL_REVPHHandle, PCM, kNumREVPHModules,
+                               HAL_HandleEnum::REVPH>
+      pH;
+  pcmHandles = &pH;
+}
+}  // namespace hal::init
+
+HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
+                                    const char* allocationLocation,
+                                    int32_t* status) {
+  hal::init::CheckInit();
+
+  if (module == 0) {
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
+                                     kNumREVPHModules, module);
+    return HAL_kInvalidHandle;
+  }
+
+  HAL_REVPHHandle handle;
+  auto pcm = pcmHandles->Allocate(module, &handle, status);
+
+  if (*status != 0) {
+    if (pcm) {
+      hal::SetLastErrorPreviouslyAllocated(status, "REV PH", module,
+                                           pcm->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
+                                       kNumREVPHModules, module);
+    }
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+  }
+
+  pcm->previousAllocation = allocationLocation ? allocationLocation : "";
+  pcm->module = module;
+
+  SimREVPHData[module].initialized = true;
+  // Enable closed loop
+  SimREVPHData[module].closedLoopEnabled = true;
+
+  return handle;
+}
+
+void HAL_FreeREVPH(HAL_REVPHHandle handle) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    pcmHandles->Free(handle);
+    return;
+  }
+  SimREVPHData[pcm->module].initialized = false;
+  pcmHandles->Free(handle);
+}
+
+HAL_Bool HAL_CheckREVPHModuleNumber(int32_t module) {
+  return module >= 1 && module < kNumREVPDHModules;
+}
+
+HAL_Bool HAL_CheckREVPHSolenoidChannel(int32_t channel) {
+  return channel < kNumREVPHChannels && channel >= 0;
+}
+
+HAL_Bool HAL_GetREVPHCompressor(HAL_REVPHHandle handle, int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimREVPHData[pcm->module].compressorOn;
+}
+
+void HAL_SetREVPHClosedLoopControl(HAL_REVPHHandle handle, HAL_Bool enabled,
+                                   int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  SimREVPHData[pcm->module].closedLoopEnabled = enabled;
+}
+
+HAL_Bool HAL_GetREVPHClosedLoopControl(HAL_REVPHHandle handle,
+                                       int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimREVPHData[pcm->module].closedLoopEnabled;
+}
+
+HAL_Bool HAL_GetREVPHPressureSwitch(HAL_REVPHHandle handle, int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  return SimREVPHData[pcm->module].pressureSwitch;
+}
+
+double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
+                                  int32_t* status) {
+  return 0;
+}
+
+double HAL_GetREVPHCompressorCurrent(HAL_REVPHHandle handle, int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  return SimREVPHData[pcm->module].compressorCurrent;
+}
+
+int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  std::scoped_lock lock{pcm->lock};
+  auto& data = SimREVPHData[pcm->module].solenoidOutput;
+  uint8_t ret = 0;
+  for (int i = 0; i < kNumREVPHChannels; i++) {
+    ret |= (data[i] << i);
+  }
+  return ret;
+}
+void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
+                           int32_t* status) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  auto& data = SimREVPHData[pcm->module].solenoidOutput;
+  std::scoped_lock lock{pcm->lock};
+  for (int i = 0; i < kNumREVPHChannels; i++) {
+    auto indexMask = (1 << i);
+    if ((mask & indexMask) != 0) {
+      data[i] = (values & indexMask) != 0;
+    }
+  }
+}
+
+void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
+                          int32_t* status) {}
diff --git a/hal/src/main/native/sim/Relay.cpp b/hal/src/main/native/sim/Relay.cpp
index acecec4..4dfcdaf 100644
--- a/hal/src/main/native/sim/Relay.cpp
+++ b/hal/src/main/native/sim/Relay.cpp
@@ -1,13 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/Relay.h"
 
+#include <string>
+
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/handles/IndexedHandleResource.h"
 #include "mockdata/RelayDataInternal.h"
@@ -18,49 +18,58 @@
 struct Relay {
   uint8_t channel;
   bool fwd;
+  std::string previousAllocation;
 };
 }  // namespace
 
 static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
                              HAL_HandleEnum::Relay>* relayHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeRelay() {
   static IndexedHandleResource<HAL_RelayHandle, Relay, kNumRelayChannels,
                                HAL_HandleEnum::Relay>
       rH;
   relayHandles = &rH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
+                                        const char* allocationLocation,
                                         int32_t* status) {
   hal::init::CheckInit();
-  if (*status != 0) return HAL_kInvalidHandle;
-
-  int16_t channel = getPortHandleChannel(portHandle);
-  if (channel == InvalidHandleIndex) {
-    *status = PARAMETER_OUT_OF_RANGE;
+  if (*status != 0) {
     return HAL_kInvalidHandle;
   }
 
-  if (!fwd) channel += kNumRelayHeaders;  // add 4 to reverse channels
-
-  auto handle = relayHandles->Allocate(channel, status);
-
-  if (*status != 0)
-    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
-
-  auto port = relayHandles->Get(handle);
-  if (port == nullptr) {  // would only occur on thread issue.
-    *status = HAL_HANDLE_ERROR;
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex || channel >= kNumRelayChannels) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Relay", 0,
+                                     kNumRelayChannels, channel);
     return HAL_kInvalidHandle;
   }
 
   if (!fwd) {
+    channel += kNumRelayHeaders;  // add 4 to reverse channels
+  }
+
+  HAL_RelayHandle handle;
+  auto port = relayHandles->Allocate(channel, &handle, status);
+
+  if (*status != 0) {
+    if (port) {
+      hal::SetLastErrorPreviouslyAllocated(status, "Relay", channel,
+                                           port->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for Relay", 0,
+                                       kNumRelayChannels, channel);
+    }
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+  }
+
+  if (!fwd) {
     // Subtract number of headers to put channel in range
     channel -= kNumRelayHeaders;
 
@@ -73,6 +82,7 @@
   }
 
   port->channel = static_cast<uint8_t>(channel);
+  port->previousAllocation = allocationLocation ? allocationLocation : "";
 
   return handle;
 }
@@ -80,11 +90,14 @@
 void HAL_FreeRelayPort(HAL_RelayHandle relayPortHandle) {
   auto port = relayHandles->Get(relayPortHandle);
   relayHandles->Free(relayPortHandle);
-  if (port == nullptr) return;
-  if (port->fwd)
+  if (port == nullptr) {
+    return;
+  }
+  if (port->fwd) {
     SimRelayData[port->channel].initializedForward = false;
-  else
+  } else {
     SimRelayData[port->channel].initializedReverse = false;
+  }
 }
 
 HAL_Bool HAL_CheckRelayChannel(int32_t channel) {
@@ -101,10 +114,11 @@
     *status = HAL_HANDLE_ERROR;
     return;
   }
-  if (port->fwd)
+  if (port->fwd) {
     SimRelayData[port->channel].forward = on;
-  else
+  } else {
     SimRelayData[port->channel].reverse = on;
+  }
 }
 
 HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status) {
@@ -113,9 +127,10 @@
     *status = HAL_HANDLE_ERROR;
     return false;
   }
-  if (port->fwd)
+  if (port->fwd) {
     return SimRelayData[port->channel].forward;
-  else
+  } else {
     return SimRelayData[port->channel].reverse;
+  }
 }
 }  // extern "C"
diff --git a/hal/src/main/native/sim/SPI.cpp b/hal/src/main/native/sim/SPI.cpp
index 1c90a98..bf362a8 100644
--- a/hal/src/main/native/sim/SPI.cpp
+++ b/hal/src/main/native/sim/SPI.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/SPI.h"
 
@@ -12,11 +9,9 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeSPI() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -35,13 +30,17 @@
 int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count) {
   return SimSPIData[port].Read(buffer, count);
 }
-void HAL_CloseSPI(HAL_SPIPort port) { SimSPIData[port].initialized = false; }
+void HAL_CloseSPI(HAL_SPIPort port) {
+  SimSPIData[port].initialized = false;
+}
 void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed) {}
 void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst,
                     HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh) {}
 void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status) {}
 void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status) {}
-int32_t HAL_GetSPIHandle(HAL_SPIPort port) { return 0; }
+int32_t HAL_GetSPIHandle(HAL_SPIPort port) {
+  return 0;
+}
 void HAL_SetSPIHandle(HAL_SPIPort port, int32_t handle) {}
 
 void HAL_InitSPIAuto(HAL_SPIPort port, int32_t bufferSize, int32_t* status) {}
diff --git a/hal/src/main/native/sim/SerialPort.cpp b/hal/src/main/native/sim/SerialPort.cpp
index 2df2ebe..83ba971 100644
--- a/hal/src/main/native/sim/SerialPort.cpp
+++ b/hal/src/main/native/sim/SerialPort.cpp
@@ -1,19 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/SerialPort.h"
 
 #include "HALInitializer.h"
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeSerialPort() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 HAL_SerialPortHandle HAL_InitializeSerialPort(HAL_SerialPort port,
@@ -29,7 +24,9 @@
   return HAL_kInvalidHandle;
 }
 
-int HAL_GetSerialFD(HAL_SerialPortHandle handle, int32_t* status) { return -1; }
+int HAL_GetSerialFD(HAL_SerialPortHandle handle, int32_t* status) {
+  return -1;
+}
 
 void HAL_SetSerialBaudRate(HAL_SerialPortHandle handle, int32_t baud,
                            int32_t* status) {}
diff --git a/hal/src/main/native/sim/SimDevice.cpp b/hal/src/main/native/sim/SimDevice.cpp
index a8f8f80..b6c637c 100644
--- a/hal/src/main/native/sim/SimDevice.cpp
+++ b/hal/src/main/native/sim/SimDevice.cpp
@@ -1,25 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/SimDevice.h"
 
-#include <wpi/SmallString.h>
-#include <wpi/raw_ostream.h>
+#include <fmt/format.h>
 
 #include "HALInitializer.h"
 #include "mockdata/SimDeviceDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeSimDevice() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -33,19 +27,29 @@
 }
 
 HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
-                                      const char* name, HAL_Bool readonly,
+                                      const char* name, int32_t direction,
                                       const struct HAL_Value* initialValue) {
-  return SimSimDeviceData->CreateValue(device, name, readonly, 0, nullptr,
-                                       *initialValue);
+  return SimSimDeviceData->CreateValue(device, name, direction, 0, nullptr,
+                                       nullptr, *initialValue);
 }
 
 HAL_SimValueHandle HAL_CreateSimValueEnum(HAL_SimDeviceHandle device,
-                                          const char* name, HAL_Bool readonly,
+                                          const char* name, int32_t direction,
                                           int32_t numOptions,
                                           const char** options,
                                           int32_t initialValue) {
-  return SimSimDeviceData->CreateValue(device, name, readonly, numOptions,
-                                       options, HAL_MakeEnum(initialValue));
+  return SimSimDeviceData->CreateValue(device, name, direction, numOptions,
+                                       options, nullptr,
+                                       HAL_MakeEnum(initialValue));
+}
+
+HAL_SimValueHandle HAL_CreateSimValueEnumDouble(
+    HAL_SimDeviceHandle device, const char* name, int32_t direction,
+    int32_t numOptions, const char** options, const double* optionValues,
+    int32_t initialValue) {
+  return SimSimDeviceData->CreateValue(device, name, direction, numOptions,
+                                       options, optionValues,
+                                       HAL_MakeEnum(initialValue));
 }
 
 void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) {
@@ -56,20 +60,17 @@
   SimSimDeviceData->SetValue(handle, *value);
 }
 
-hal::SimDevice::SimDevice(const char* name, int index) {
-  wpi::SmallString<128> fullname;
-  wpi::raw_svector_ostream os(fullname);
-  os << name << '[' << index << ']';
+void HAL_ResetSimValue(HAL_SimValueHandle handle) {
+  SimSimDeviceData->ResetValue(handle);
+}
 
-  m_handle = HAL_CreateSimDevice(fullname.c_str());
+hal::SimDevice::SimDevice(const char* name, int index) {
+  m_handle = HAL_CreateSimDevice(fmt::format("{}[{}]", name, index).c_str());
 }
 
 hal::SimDevice::SimDevice(const char* name, int index, int channel) {
-  wpi::SmallString<128> fullname;
-  wpi::raw_svector_ostream os(fullname);
-  os << name << '[' << index << ',' << channel << ']';
-
-  m_handle = HAL_CreateSimDevice(fullname.c_str());
+  m_handle = HAL_CreateSimDevice(
+      fmt::format("{}[{},{}]", name, index, channel).c_str());
 }
 
 }  // extern "C"
diff --git a/hal/src/main/native/sim/Solenoid.cpp b/hal/src/main/native/sim/Solenoid.cpp
deleted file mode 100644
index 1881a32..0000000
--- a/hal/src/main/native/sim/Solenoid.cpp
+++ /dev/null
@@ -1,145 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "hal/Solenoid.h"
-
-#include "HALInitializer.h"
-#include "PortsInternal.h"
-#include "hal/Errors.h"
-#include "hal/handles/HandlesInternal.h"
-#include "hal/handles/IndexedHandleResource.h"
-#include "hal/simulation/PCMData.h"
-
-namespace {
-struct Solenoid {
-  uint8_t module;
-  uint8_t channel;
-};
-}  // namespace
-
-using namespace hal;
-
-static IndexedHandleResource<HAL_SolenoidHandle, Solenoid,
-                             kNumPCMModules * kNumSolenoidChannels,
-                             HAL_HandleEnum::Solenoid>* solenoidHandles;
-
-namespace hal {
-namespace init {
-void InitializeSolenoid() {
-  static IndexedHandleResource<HAL_SolenoidHandle, Solenoid,
-                               kNumPCMModules * kNumSolenoidChannels,
-                               HAL_HandleEnum::Solenoid>
-      sH;
-  solenoidHandles = &sH;
-}
-}  // namespace init
-}  // namespace hal
-
-extern "C" {
-HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle,
-                                              int32_t* status) {
-  hal::init::CheckInit();
-  int16_t channel = getPortHandleChannel(portHandle);
-  int16_t module = getPortHandleModule(portHandle);
-  if (channel == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return HAL_kInvalidHandle;
-  }
-
-  if (!HAL_CheckSolenoidChannel(channel)) {
-    *status = RESOURCE_OUT_OF_RANGE;
-    return HAL_kInvalidHandle;
-  }
-
-  if (!HAL_CheckSolenoidModule(module)) {
-    *status = RESOURCE_OUT_OF_RANGE;
-    return HAL_kInvalidHandle;
-  }
-
-  auto handle = solenoidHandles->Allocate(
-      module * kNumSolenoidChannels + channel, status);
-  if (handle == HAL_kInvalidHandle) {  // out of resources
-    *status = NO_AVAILABLE_RESOURCES;
-    return HAL_kInvalidHandle;
-  }
-  auto solenoidPort = solenoidHandles->Get(handle);
-  if (solenoidPort == nullptr) {  // would only occur on thread issues
-    *status = HAL_HANDLE_ERROR;
-    return HAL_kInvalidHandle;
-  }
-  solenoidPort->module = static_cast<uint8_t>(module);
-  solenoidPort->channel = static_cast<uint8_t>(channel);
-
-  HALSIM_SetPCMSolenoidInitialized(module, channel, true);
-
-  return handle;
-}
-void HAL_FreeSolenoidPort(HAL_SolenoidHandle solenoidPortHandle) {
-  auto port = solenoidHandles->Get(solenoidPortHandle);
-  if (port == nullptr) return;
-  solenoidHandles->Free(solenoidPortHandle);
-  HALSIM_SetPCMSolenoidInitialized(port->module, port->channel, false);
-}
-HAL_Bool HAL_CheckSolenoidModule(int32_t module) {
-  return module < kNumPCMModules && module >= 0;
-}
-
-HAL_Bool HAL_CheckSolenoidChannel(int32_t channel) {
-  return channel < kNumSolenoidChannels && channel >= 0;
-}
-HAL_Bool HAL_GetSolenoid(HAL_SolenoidHandle solenoidPortHandle,
-                         int32_t* status) {
-  auto port = solenoidHandles->Get(solenoidPortHandle);
-  if (port == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-
-  return HALSIM_GetPCMSolenoidOutput(port->module, port->channel);
-}
-int32_t HAL_GetAllSolenoids(int32_t module, int32_t* status) {
-  int32_t total = 0;
-  for (int i = 0; i < kNumSolenoidChannels; i++) {
-    int32_t channel = HALSIM_GetPCMSolenoidOutput(module, i) ? 1 : 0;
-    total = total + (channel << i);
-  }
-
-  return total;
-}
-void HAL_SetSolenoid(HAL_SolenoidHandle solenoidPortHandle, HAL_Bool value,
-                     int32_t* status) {
-  auto port = solenoidHandles->Get(solenoidPortHandle);
-  if (port == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  HALSIM_SetPCMSolenoidOutput(port->module, port->channel, value);
-}
-
-void HAL_SetAllSolenoids(int32_t module, int32_t state, int32_t* status) {
-  for (int i = 0; i < kNumSolenoidChannels; i++) {
-    int set = state & 1;
-    HALSIM_SetPCMSolenoidOutput(module, i, set);
-    state >>= 1;
-  }
-}
-
-int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status) {
-  return 0;
-}
-HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status) {
-  return 0;
-}
-HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status) {
-  return 0;
-}
-void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status) {}
-void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
-                            int32_t durMS, int32_t* status) {}
-void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status) {}
-}  // extern "C"
diff --git a/hal/src/main/native/sim/Threads.cpp b/hal/src/main/native/sim/Threads.cpp
index 2aa2c4b..94b6090 100644
--- a/hal/src/main/native/sim/Threads.cpp
+++ b/hal/src/main/native/sim/Threads.cpp
@@ -1,17 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/Threads.h"
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeThreads() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 int32_t HAL_GetThreadPriority(NativeThreadHandle handle, HAL_Bool* isRealTime,
                               int32_t* status) {
diff --git a/hal/src/main/native/sim/mockdata/AccelerometerData.cpp b/hal/src/main/native/sim/mockdata/AccelerometerData.cpp
index 66e129a..8ed4d78 100644
--- a/hal/src/main/native/sim/mockdata/AccelerometerData.cpp
+++ b/hal/src/main/native/sim/mockdata/AccelerometerData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "AccelerometerDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAccelerometerData() {
   static AccelerometerData sad[1];
   ::hal::SimAccelerometerData = sad;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 AccelerometerData* hal::SimAccelerometerData;
 void AccelerometerData::ResetData() {
diff --git a/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h b/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h
index e2e0a80..24be83e 100644
--- a/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AccelerometerDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/AddressableLEDData.cpp b/hal/src/main/native/sim/mockdata/AddressableLEDData.cpp
index fe4611e..0945ec9 100644
--- a/hal/src/main/native/sim/mockdata/AddressableLEDData.cpp
+++ b/hal/src/main/native/sim/mockdata/AddressableLEDData.cpp
@@ -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.
 
 #include <algorithm>
 #include <cstring>
@@ -13,14 +10,12 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAddressableLEDData() {
   static AddressableLEDData sad[kNumAddressableLEDs];
   ::hal::SimAddressableLEDData = sad;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 AddressableLEDData* hal::SimAddressableLEDData;
 
@@ -44,7 +39,9 @@
 int32_t AddressableLEDData::GetData(HAL_AddressableLEDData* d) {
   std::scoped_lock lock(m_dataMutex);
   int32_t len = length;
-  if (d) std::memcpy(d, m_data, len * sizeof(d[0]));
+  if (d) {
+    std::memcpy(d, m_data, len * sizeof(d[0]));
+  }
   return len;
 }
 
@@ -53,8 +50,9 @@
 int32_t HALSIM_FindAddressableLEDForChannel(int32_t channel) {
   for (int i = 0; i < kNumAddressableLEDs; ++i) {
     if (SimAddressableLEDData[i].initialized &&
-        SimAddressableLEDData[i].outputPort == channel)
+        SimAddressableLEDData[i].outputPort == channel) {
       return i;
+    }
   }
   return -1;
 }
diff --git a/hal/src/main/native/sim/mockdata/AddressableLEDDataInternal.h b/hal/src/main/native/sim/mockdata/AddressableLEDDataInternal.h
index f0b7998..3382eed 100644
--- a/hal/src/main/native/sim/mockdata/AddressableLEDDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AddressableLEDDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/AnalogGyroData.cpp b/hal/src/main/native/sim/mockdata/AnalogGyroData.cpp
index 2508d9b..bb4e278 100644
--- a/hal/src/main/native/sim/mockdata/AnalogGyroData.cpp
+++ b/hal/src/main/native/sim/mockdata/AnalogGyroData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "AnalogGyroDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogGyroData() {
   static AnalogGyroData agd[kNumAccumulators];
   ::hal::SimAnalogGyroData = agd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 AnalogGyroData* hal::SimAnalogGyroData;
 void AnalogGyroData::ResetData() {
diff --git a/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h
index ff12b60..d88c56d 100644
--- a/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AnalogGyroDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/AnalogInData.cpp b/hal/src/main/native/sim/mockdata/AnalogInData.cpp
index a2a871c..a93cad0 100644
--- a/hal/src/main/native/sim/mockdata/AnalogInData.cpp
+++ b/hal/src/main/native/sim/mockdata/AnalogInData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "AnalogInDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogInData() {
   static AnalogInData sind[kNumAnalogInputs];
   ::hal::SimAnalogInData = sind;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 AnalogInData* hal::SimAnalogInData;
 void AnalogInData::ResetData() {
diff --git a/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h
index 90d707c..953c8f8 100644
--- a/hal/src/main/native/sim/mockdata/AnalogInDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AnalogInDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/AnalogOutData.cpp b/hal/src/main/native/sim/mockdata/AnalogOutData.cpp
index d4b9116..0ec39e0 100644
--- a/hal/src/main/native/sim/mockdata/AnalogOutData.cpp
+++ b/hal/src/main/native/sim/mockdata/AnalogOutData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "AnalogOutDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogOutData() {
   static AnalogOutData siod[kNumAnalogOutputs];
   ::hal::SimAnalogOutData = siod;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 AnalogOutData* hal::SimAnalogOutData;
 void AnalogOutData::ResetData() {
diff --git a/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h
index 779ee96..d4a61b2 100644
--- a/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AnalogOutDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/AnalogTriggerData.cpp b/hal/src/main/native/sim/mockdata/AnalogTriggerData.cpp
index ba33522..72184da 100644
--- a/hal/src/main/native/sim/mockdata/AnalogTriggerData.cpp
+++ b/hal/src/main/native/sim/mockdata/AnalogTriggerData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "AnalogTriggerDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogTriggerData() {
   static AnalogTriggerData satd[kNumAnalogTriggers];
   ::hal::SimAnalogTriggerData = satd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 AnalogTriggerData* hal::SimAnalogTriggerData;
 void AnalogTriggerData::ResetData() {
@@ -32,8 +27,9 @@
 int32_t HALSIM_FindAnalogTriggerForChannel(int32_t channel) {
   for (int i = 0; i < kNumAnalogTriggers; ++i) {
     if (SimAnalogTriggerData[i].initialized &&
-        SimAnalogTriggerData[i].inputPort == channel)
+        SimAnalogTriggerData[i].inputPort == channel) {
       return i;
+    }
   }
   return -1;
 }
diff --git a/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h b/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h
index 74fe5f8..16aab79 100644
--- a/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/AnalogTriggerDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/CTREPCMData.cpp b/hal/src/main/native/sim/mockdata/CTREPCMData.cpp
new file mode 100644
index 0000000..bfc0b61
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/CTREPCMData.cpp
@@ -0,0 +1,83 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "../PortsInternal.h"
+#include "CTREPCMDataInternal.h"
+
+using namespace hal;
+
+namespace hal::init {
+void InitializeCTREPCMData() {
+  static CTREPCMData spd[kNumCTREPCMModules];
+  ::hal::SimCTREPCMData = spd;
+}
+}  // namespace hal::init
+
+CTREPCMData* hal::SimCTREPCMData;
+void CTREPCMData::ResetData() {
+  for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
+    solenoidOutput[i].Reset(false);
+  }
+  initialized.Reset(false);
+  compressorOn.Reset(false);
+  closedLoopEnabled.Reset(true);
+  pressureSwitch.Reset(false);
+  compressorCurrent.Reset(0.0);
+}
+
+extern "C" {
+void HALSIM_ResetCTREPCMData(int32_t index) {
+  SimCTREPCMData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                  \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, CTREPCM##CAPINAME, \
+                               SimCTREPCMData, LOWERNAME)
+
+HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(HAL_Bool, HALSIM, CTREPCMSolenoidOutput,
+                                     SimCTREPCMData, solenoidOutput)
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(HAL_Bool, CompressorOn, compressorOn)
+DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, closedLoopEnabled)
+DEFINE_CAPI(HAL_Bool, PressureSwitch, pressureSwitch)
+DEFINE_CAPI(double, CompressorCurrent, compressorCurrent)
+
+void HALSIM_GetCTREPCMAllSolenoids(int32_t index, uint8_t* values) {
+  auto& data = SimCTREPCMData[index].solenoidOutput;
+  uint8_t ret = 0;
+  for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
+    ret |= (data[i] << i);
+  }
+  *values = ret;
+}
+
+void HALSIM_SetCTREPCMAllSolenoids(int32_t index, uint8_t values) {
+  auto& data = SimCTREPCMData[index].solenoidOutput;
+  for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
+    data[i] = (values & 0x1) != 0;
+    values >>= 1;
+  }
+}
+
+#define REGISTER(NAME) \
+  SimCTREPCMData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterCTREPCMAllNonSolenoidCallbacks(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(compressorOn);
+  REGISTER(closedLoopEnabled);
+  REGISTER(pressureSwitch);
+  REGISTER(compressorCurrent);
+}
+
+void HALSIM_RegisterCTREPCMAllSolenoidCallbacks(int32_t index, int32_t channel,
+                                                HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify) {
+  REGISTER(solenoidOutput[channel]);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/CTREPCMDataInternal.h b/hal/src/main/native/sim/mockdata/CTREPCMDataInternal.h
new file mode 100644
index 0000000..56a6a09
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/CTREPCMDataInternal.h
@@ -0,0 +1,43 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 "../PortsInternal.h"
+#include "hal/simulation/CTREPCMData.h"
+#include "hal/simulation/SimDataValue.h"
+
+namespace hal {
+class CTREPCMData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(SolenoidOutput)
+  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorOn)
+  HAL_SIMDATAVALUE_DEFINE_NAME(ClosedLoopEnabled)
+  HAL_SIMDATAVALUE_DEFINE_NAME(PressureSwitch)
+  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorCurrent)
+
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr HAL_Bool
+  GetSolenoidOutputDefault() {
+    return false;
+  }
+
+ public:
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetSolenoidOutputName,
+               GetSolenoidOutputDefault>
+      solenoidOutput[kNumCTRESolenoidChannels];
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetCompressorOnName> compressorOn{
+      false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetClosedLoopEnabledName>
+      closedLoopEnabled{true};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetPressureSwitchName> pressureSwitch{
+      false};
+  SimDataValue<double, HAL_MakeDouble, GetCompressorCurrentName>
+      compressorCurrent{0.0};
+
+  virtual void ResetData();
+};
+extern CTREPCMData* SimCTREPCMData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/CanDataInternal.cpp b/hal/src/main/native/sim/mockdata/CanDataInternal.cpp
index e37d865..0ace401 100644
--- a/hal/src/main/native/sim/mockdata/CanDataInternal.cpp
+++ b/hal/src/main/native/sim/mockdata/CanDataInternal.cpp
@@ -1,22 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "CanDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeCanData() {
   static CanData scd;
   ::hal::SimCanData = &scd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 CanData* hal::SimCanData;
 
@@ -31,7 +26,9 @@
 
 extern "C" {
 
-void HALSIM_ResetCanData(void) { SimCanData->ResetData(); }
+void HALSIM_ResetCanData(void) {
+  SimCanData->ResetData();
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                             \
   HAL_SIMCALLBACKREGISTRY_DEFINE_CAPI_NOINDEX(TYPE, HALSIM, Can##CAPINAME, \
diff --git a/hal/src/main/native/sim/mockdata/CanDataInternal.h b/hal/src/main/native/sim/mockdata/CanDataInternal.h
index df5b290..c2b7282 100644
--- a/hal/src/main/native/sim/mockdata/CanDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/CanDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/DIOData.cpp b/hal/src/main/native/sim/mockdata/DIOData.cpp
index a9c61fd..cdca84b 100644
--- a/hal/src/main/native/sim/mockdata/DIOData.cpp
+++ b/hal/src/main/native/sim/mockdata/DIOData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "DIODataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDIOData() {
   static DIOData sdd[kNumDigitalChannels];
   ::hal::SimDIOData = sdd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 DIOData* hal::SimDIOData;
 void DIOData::ResetData() {
@@ -30,7 +25,9 @@
 }
 
 extern "C" {
-void HALSIM_ResetDIOData(int32_t index) { SimDIOData[index].ResetData(); }
+void HALSIM_ResetDIOData(int32_t index) {
+  SimDIOData[index].ResetData();
+}
 
 HAL_SimDeviceHandle HALSIM_GetDIOSimDevice(int32_t index) {
   return SimDIOData[index].simDevice;
diff --git a/hal/src/main/native/sim/mockdata/DIODataInternal.h b/hal/src/main/native/sim/mockdata/DIODataInternal.h
index c3266d5..9e6828b 100644
--- a/hal/src/main/native/sim/mockdata/DIODataInternal.h
+++ b/hal/src/main/native/sim/mockdata/DIODataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/DigitalPWMData.cpp b/hal/src/main/native/sim/mockdata/DigitalPWMData.cpp
index 541d7cf..da4236a 100644
--- a/hal/src/main/native/sim/mockdata/DigitalPWMData.cpp
+++ b/hal/src/main/native/sim/mockdata/DigitalPWMData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "DigitalPWMDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDigitalPWMData() {
   static DigitalPWMData sdpd[kNumDigitalPWMOutputs];
   ::hal::SimDigitalPWMData = sdpd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 DigitalPWMData* hal::SimDigitalPWMData;
 void DigitalPWMData::ResetData() {
@@ -29,8 +24,10 @@
 extern "C" {
 int32_t HALSIM_FindDigitalPWMForChannel(int32_t channel) {
   for (int i = 0; i < kNumDigitalPWMOutputs; ++i) {
-    if (SimDigitalPWMData[i].initialized && SimDigitalPWMData[i].pin == channel)
+    if (SimDigitalPWMData[i].initialized &&
+        SimDigitalPWMData[i].pin == channel) {
       return i;
+    }
   }
   return -1;
 }
diff --git a/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h b/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h
index f2c7a5e..fe06389 100644
--- a/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/DigitalPWMDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/DriverStationData.cpp b/hal/src/main/native/sim/mockdata/DriverStationData.cpp
index dae1dd4..c704f2b 100644
--- a/hal/src/main/native/sim/mockdata/DriverStationData.cpp
+++ b/hal/src/main/native/sim/mockdata/DriverStationData.cpp
@@ -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.
 
 #include <cstring>
 
@@ -12,18 +9,18 @@
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDriverStationData() {
   static DriverStationData dsd;
   ::hal::SimDriverStationData = &dsd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 DriverStationData* hal::SimDriverStationData;
 
-DriverStationData::DriverStationData() { ResetData(); }
+DriverStationData::DriverStationData() {
+  ResetData();
+}
 
 void DriverStationData::ResetData() {
   enabled.Reset(false);
@@ -63,7 +60,8 @@
   int32_t DriverStationData::RegisterJoystick##name##Callback(                 \
       int32_t joystickNum, HAL_Joystick##name##Callback callback, void* param, \
       HAL_Bool initialNotify) {                                                \
-    if (joystickNum < 0 || joystickNum >= kNumJoysticks) return 0;             \
+    if (joystickNum < 0 || joystickNum >= kNumJoysticks)                       \
+      return 0;                                                                \
     std::scoped_lock lock(m_joystickDataMutex);                                \
     int32_t uid = m_joystick##name##Callbacks.Register(callback, param);       \
     if (initialNotify) {                                                       \
@@ -82,14 +80,16 @@
                                                                            \
   void DriverStationData::GetJoystick##name(int32_t joystickNum,           \
                                             HAL_Joystick##name* d) {       \
-    if (joystickNum < 0 || joystickNum >= kNumJoysticks) return;           \
+    if (joystickNum < 0 || joystickNum >= kNumJoysticks)                   \
+      return;                                                              \
     std::scoped_lock lock(m_joystickDataMutex);                            \
     *d = m_joystickData[joystickNum].data##data2;                          \
   }                                                                        \
                                                                            \
   void DriverStationData::SetJoystick##name(int32_t joystickNum,           \
                                             const HAL_Joystick##name* d) { \
-    if (joystickNum < 0 || joystickNum >= kNumJoysticks) return;           \
+    if (joystickNum < 0 || joystickNum >= kNumJoysticks)                   \
+      return;                                                              \
     std::scoped_lock lock(m_joystickDataMutex);                            \
     m_joystickData[joystickNum].data##data2 = *d;                          \
     m_joystick##name##Callbacks(joystickNum, d);                           \
@@ -103,14 +103,18 @@
 
 void DriverStationData::GetJoystickDescriptor(
     int32_t joystickNum, HAL_JoystickDescriptor* descriptor) {
-  if (joystickNum < 0 || joystickNum >= kNumJoysticks) return;
+  if (joystickNum < 0 || joystickNum >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   *descriptor = m_joystickData[joystickNum].descriptor;
 }
 
 void DriverStationData::SetJoystickDescriptor(
     int32_t joystickNum, const HAL_JoystickDescriptor* descriptor) {
-  if (joystickNum < 0 || joystickNum >= kNumJoysticks) return;
+  if (joystickNum < 0 || joystickNum >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[joystickNum].descriptor = *descriptor;
   // Always ensure name is null terminated
@@ -121,8 +125,9 @@
 int32_t DriverStationData::RegisterJoystickOutputsCallback(
     int32_t joystickNum, HAL_JoystickOutputsCallback callback, void* param,
     HAL_Bool initialNotify) {
-  if (joystickNum < 0 || joystickNum >= DriverStationData::kNumJoysticks)
+  if (joystickNum < 0 || joystickNum >= DriverStationData::kNumJoysticks) {
     return 0;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   int32_t uid = m_joystickOutputsCallbacks.Register(callback, param);
   if (initialNotify) {
@@ -141,7 +146,9 @@
                                            int64_t* outputs,
                                            int32_t* leftRumble,
                                            int32_t* rightRumble) {
-  if (joystickNum < 0 || joystickNum >= kNumJoysticks) return;
+  if (joystickNum < 0 || joystickNum >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   *leftRumble = m_joystickData[joystickNum].outputs.leftRumble;
   *outputs = m_joystickData[joystickNum].outputs.outputs;
@@ -151,7 +158,9 @@
 void DriverStationData::SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
                                            int32_t leftRumble,
                                            int32_t rightRumble) {
-  if (joystickNum < 0 || joystickNum >= kNumJoysticks) return;
+  if (joystickNum < 0 || joystickNum >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[joystickNum].outputs.leftRumble = leftRumble;
   m_joystickData[joystickNum].outputs.outputs = outputs;
@@ -207,23 +216,32 @@
   m_newDataCallbacks(&empty);
 }
 
-void DriverStationData::NotifyNewData() { HAL_ReleaseDSMutex(); }
+void DriverStationData::NotifyNewData() {
+  HAL_ReleaseDSMutex();
+}
 
 void DriverStationData::SetJoystickButton(int32_t stick, int32_t button,
                                           HAL_Bool state) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
-  if (state)
+  if (state) {
     m_joystickData[stick].buttons.buttons |= 1 << (button - 1);
-  else
+  } else {
     m_joystickData[stick].buttons.buttons &= ~(1 << (button - 1));
+  }
   m_joystickButtonsCallbacks(stick, &m_joystickData[stick].buttons);
 }
 
 void DriverStationData::SetJoystickAxis(int32_t stick, int32_t axis,
                                         double value) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
-  if (axis < 0 || axis >= HAL_kMaxJoystickAxes) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
+  if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].axes.axes[axis] = value;
   m_joystickAxesCallbacks(stick, &m_joystickData[stick].axes);
@@ -231,22 +249,30 @@
 
 void DriverStationData::SetJoystickPOV(int32_t stick, int32_t pov,
                                        int32_t value) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
-  if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
+  if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].povs.povs[pov] = value;
   m_joystickPOVsCallbacks(stick, &m_joystickData[stick].povs);
 }
 
 void DriverStationData::SetJoystickButtons(int32_t stick, uint32_t buttons) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].buttons.buttons = buttons;
   m_joystickButtonsCallbacks(stick, &m_joystickData[stick].buttons);
 }
 
 void DriverStationData::SetJoystickAxisCount(int32_t stick, int32_t count) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].axes.count = count;
   m_joystickData[stick].descriptor.axisCount = count;
@@ -255,7 +281,9 @@
 }
 
 void DriverStationData::SetJoystickPOVCount(int32_t stick, int32_t count) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].povs.count = count;
   m_joystickData[stick].descriptor.povCount = count;
@@ -264,7 +292,9 @@
 }
 
 void DriverStationData::SetJoystickButtonCount(int32_t stick, int32_t count) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].buttons.count = count;
   m_joystickData[stick].descriptor.buttonCount = count;
@@ -288,21 +318,27 @@
 }
 
 void DriverStationData::SetJoystickIsXbox(int32_t stick, HAL_Bool isXbox) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].descriptor.isXbox = isXbox;
   m_joystickDescriptorCallbacks(stick, &m_joystickData[stick].descriptor);
 }
 
 void DriverStationData::SetJoystickType(int32_t stick, int32_t type) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].descriptor.type = type;
   m_joystickDescriptorCallbacks(stick, &m_joystickData[stick].descriptor);
 }
 
 void DriverStationData::SetJoystickName(int32_t stick, const char* name) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   std::strncpy(m_joystickData[stick].descriptor.name, name,
                sizeof(m_joystickData[stick].descriptor.name) - 1);
@@ -312,8 +348,12 @@
 
 void DriverStationData::SetJoystickAxisType(int32_t stick, int32_t axis,
                                             int32_t type) {
-  if (stick < 0 || stick >= kNumJoysticks) return;
-  if (axis < 0 || axis >= HAL_kMaxJoystickAxes) return;
+  if (stick < 0 || stick >= kNumJoysticks) {
+    return;
+  }
+  if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
+    return;
+  }
   std::scoped_lock lock(m_joystickDataMutex);
   m_joystickData[stick].descriptor.axisTypes[axis] = type;
   m_joystickDescriptorCallbacks(stick, &m_joystickData[stick].descriptor);
@@ -354,7 +394,9 @@
 }
 
 extern "C" {
-void HALSIM_ResetDriverStationData(void) { SimDriverStationData->ResetData(); }
+void HALSIM_ResetDriverStationData(void) {
+  SimDriverStationData->ResetData();
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                                \
   HAL_SIMDATAVALUE_DEFINE_CAPI_NOINDEX(TYPE, HALSIM, DriverStation##CAPINAME, \
diff --git a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h
index 2a50742..e0f545e 100644
--- a/hal/src/main/native/sim/mockdata/DriverStationDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/DriverStationDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/DutyCycleData.cpp b/hal/src/main/native/sim/mockdata/DutyCycleData.cpp
index 660522d..de677a5 100644
--- a/hal/src/main/native/sim/mockdata/DutyCycleData.cpp
+++ b/hal/src/main/native/sim/mockdata/DutyCycleData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "../PortsInternal.h"
 #include "DutyCycleDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDutyCycleData() {
   static DutyCycleData sed[kNumDutyCycles];
   ::hal::SimDutyCycleData = sed;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 DutyCycleData* hal::SimDutyCycleData;
 
@@ -33,8 +28,9 @@
 int32_t HALSIM_FindDutyCycleForChannel(int32_t channel) {
   for (int i = 0; i < kNumDutyCycles; ++i) {
     if (SimDutyCycleData[i].initialized &&
-        SimDutyCycleData[i].digitalChannel == channel)
+        SimDutyCycleData[i].digitalChannel == channel) {
       return i;
+    }
   }
   return -1;
 }
diff --git a/hal/src/main/native/sim/mockdata/DutyCycleDataInternal.h b/hal/src/main/native/sim/mockdata/DutyCycleDataInternal.h
index e69f9aa..0eb8aff 100644
--- a/hal/src/main/native/sim/mockdata/DutyCycleDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/DutyCycleDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/EncoderData.cpp b/hal/src/main/native/sim/mockdata/EncoderData.cpp
index 0b17ac3..62ff744 100644
--- a/hal/src/main/native/sim/mockdata/EncoderData.cpp
+++ b/hal/src/main/native/sim/mockdata/EncoderData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "EncoderDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeEncoderData() {
   static EncoderData sed[kNumEncoders];
   ::hal::SimEncoderData = sed;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 EncoderData* hal::SimEncoderData;
 void EncoderData::ResetData() {
@@ -38,10 +33,13 @@
 extern "C" {
 int32_t HALSIM_FindEncoderForChannel(int32_t channel) {
   for (int i = 0; i < kNumEncoders; ++i) {
-    if (!SimEncoderData[i].initialized) continue;
+    if (!SimEncoderData[i].initialized) {
+      continue;
+    }
     if (SimEncoderData[i].digitalChannelA == channel ||
-        SimEncoderData[i].digitalChannelB == channel)
+        SimEncoderData[i].digitalChannelB == channel) {
       return i;
+    }
   }
   return -1;
 }
diff --git a/hal/src/main/native/sim/mockdata/EncoderDataInternal.h b/hal/src/main/native/sim/mockdata/EncoderDataInternal.h
index 3848f1d..bd0db11 100644
--- a/hal/src/main/native/sim/mockdata/EncoderDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/EncoderDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/I2CData.cpp b/hal/src/main/native/sim/mockdata/I2CData.cpp
index 713064e..0ac813d 100644
--- a/hal/src/main/native/sim/mockdata/I2CData.cpp
+++ b/hal/src/main/native/sim/mockdata/I2CData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "I2CDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeI2CData() {
   static I2CData sid[2];
   ::hal::SimI2CData = sid;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 I2CData* hal::SimI2CData;
 
@@ -37,7 +32,9 @@
 }
 
 extern "C" {
-void HALSIM_ResetI2CData(int32_t index) { SimI2CData[index].ResetData(); }
+void HALSIM_ResetI2CData(int32_t index) {
+  SimI2CData[index].ResetData();
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
   HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, I2C##CAPINAME, SimI2CData, \
diff --git a/hal/src/main/native/sim/mockdata/I2CDataInternal.h b/hal/src/main/native/sim/mockdata/I2CDataInternal.h
index 4822222..6dd4739 100644
--- a/hal/src/main/native/sim/mockdata/I2CDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/I2CDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/PCMData.cpp b/hal/src/main/native/sim/mockdata/PCMData.cpp
deleted file mode 100644
index 6193b05..0000000
--- a/hal/src/main/native/sim/mockdata/PCMData.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "../PortsInternal.h"
-#include "PCMDataInternal.h"
-
-using namespace hal;
-
-namespace hal {
-namespace init {
-void InitializePCMData() {
-  static PCMData spd[kNumPCMModules];
-  ::hal::SimPCMData = spd;
-}
-}  // namespace init
-}  // namespace hal
-
-PCMData* hal::SimPCMData;
-void PCMData::ResetData() {
-  for (int i = 0; i < kNumSolenoidChannels; i++) {
-    solenoidInitialized[i].Reset(false);
-    solenoidOutput[i].Reset(false);
-  }
-  compressorInitialized.Reset(false);
-  compressorOn.Reset(false);
-  closedLoopEnabled.Reset(true);
-  pressureSwitch.Reset(false);
-  compressorCurrent.Reset(0.0);
-}
-
-extern "C" {
-void HALSIM_ResetPCMData(int32_t index) { SimPCMData[index].ResetData(); }
-
-#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
-  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PCM##CAPINAME, SimPCMData, \
-                               LOWERNAME)
-
-HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(HAL_Bool, HALSIM, PCMSolenoidInitialized,
-                                     SimPCMData, solenoidInitialized)
-HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(HAL_Bool, HALSIM, PCMSolenoidOutput,
-                                     SimPCMData, solenoidOutput)
-DEFINE_CAPI(HAL_Bool, CompressorInitialized, compressorInitialized)
-DEFINE_CAPI(HAL_Bool, CompressorOn, compressorOn)
-DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, closedLoopEnabled)
-DEFINE_CAPI(HAL_Bool, PressureSwitch, pressureSwitch)
-DEFINE_CAPI(double, CompressorCurrent, compressorCurrent)
-
-void HALSIM_GetPCMAllSolenoids(int32_t index, uint8_t* values) {
-  auto& data = SimPCMData[index].solenoidOutput;
-  uint8_t ret = 0;
-  for (int i = 0; i < kNumSolenoidChannels; i++) {
-    ret |= (data[i] << i);
-  }
-  *values = ret;
-}
-
-void HALSIM_SetPCMAllSolenoids(int32_t index, uint8_t values) {
-  auto& data = SimPCMData[index].solenoidOutput;
-  for (int i = 0; i < kNumSolenoidChannels; i++) {
-    data[i] = (values & 0x1) != 0;
-    values >>= 1;
-  }
-}
-
-#define REGISTER(NAME) \
-  SimPCMData[index].NAME.RegisterCallback(callback, param, initialNotify)
-
-void HALSIM_RegisterPCMAllNonSolenoidCallbacks(int32_t index,
-                                               HAL_NotifyCallback callback,
-                                               void* param,
-                                               HAL_Bool initialNotify) {
-  REGISTER(compressorInitialized);
-  REGISTER(compressorOn);
-  REGISTER(closedLoopEnabled);
-  REGISTER(pressureSwitch);
-  REGISTER(compressorCurrent);
-}
-
-void HALSIM_RegisterPCMAllSolenoidCallbacks(int32_t index, int32_t channel,
-                                            HAL_NotifyCallback callback,
-                                            void* param,
-                                            HAL_Bool initialNotify) {
-  REGISTER(solenoidInitialized[channel]);
-  REGISTER(solenoidOutput[channel]);
-}
-}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/PCMDataInternal.h b/hal/src/main/native/sim/mockdata/PCMDataInternal.h
deleted file mode 100644
index 0d3752e..0000000
--- a/hal/src/main/native/sim/mockdata/PCMDataInternal.h
+++ /dev/null
@@ -1,54 +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 "../PortsInternal.h"
-#include "hal/simulation/PCMData.h"
-#include "hal/simulation/SimDataValue.h"
-
-namespace hal {
-class PCMData {
-  HAL_SIMDATAVALUE_DEFINE_NAME(SolenoidInitialized)
-  HAL_SIMDATAVALUE_DEFINE_NAME(SolenoidOutput)
-  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorInitialized)
-  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorOn)
-  HAL_SIMDATAVALUE_DEFINE_NAME(ClosedLoopEnabled)
-  HAL_SIMDATAVALUE_DEFINE_NAME(PressureSwitch)
-  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorCurrent)
-
-  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr HAL_Bool
-  GetSolenoidInitializedDefault() {
-    return false;
-  }
-  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr HAL_Bool
-  GetSolenoidOutputDefault() {
-    return false;
-  }
-
- public:
-  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetSolenoidInitializedName,
-               GetSolenoidInitializedDefault>
-      solenoidInitialized[kNumSolenoidChannels];
-  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetSolenoidOutputName,
-               GetSolenoidOutputDefault>
-      solenoidOutput[kNumSolenoidChannels];
-  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetCompressorInitializedName>
-      compressorInitialized{false};
-  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetCompressorOnName> compressorOn{
-      false};
-  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetClosedLoopEnabledName>
-      closedLoopEnabled{true};
-  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetPressureSwitchName> pressureSwitch{
-      false};
-  SimDataValue<double, HAL_MakeDouble, GetCompressorCurrentName>
-      compressorCurrent{0.0};
-
-  virtual void ResetData();
-};
-extern PCMData* SimPCMData;
-}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/PDPData.cpp b/hal/src/main/native/sim/mockdata/PDPData.cpp
deleted file mode 100644
index 1c150bb..0000000
--- a/hal/src/main/native/sim/mockdata/PDPData.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "../PortsInternal.h"
-#include "PDPDataInternal.h"
-
-using namespace hal;
-
-namespace hal {
-namespace init {
-void InitializePDPData() {
-  static PDPData spd[kNumPDPModules];
-  ::hal::SimPDPData = spd;
-}
-}  // namespace init
-}  // namespace hal
-
-PDPData* hal::SimPDPData;
-void PDPData::ResetData() {
-  initialized.Reset(false);
-  temperature.Reset(0.0);
-  voltage.Reset(12.0);
-  for (int i = 0; i < kNumPDPChannels; i++) {
-    current[i].Reset(0.0);
-  }
-}
-
-extern "C" {
-void HALSIM_ResetPDPData(int32_t index) { SimPDPData[index].ResetData(); }
-
-#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
-  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PDP##CAPINAME, SimPDPData, \
-                               LOWERNAME)
-
-DEFINE_CAPI(HAL_Bool, Initialized, initialized)
-DEFINE_CAPI(double, Temperature, temperature)
-DEFINE_CAPI(double, Voltage, voltage)
-HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(double, HALSIM, PDPCurrent, SimPDPData,
-                                     current)
-
-void HALSIM_GetPDPAllCurrents(int32_t index, double* currents) {
-  auto& data = SimPDPData[index].current;
-  for (int i = 0; i < kNumPDPChannels; i++) {
-    currents[i] = data[i];
-  }
-}
-
-void HALSIM_SetPDPAllCurrents(int32_t index, const double* currents) {
-  auto& data = SimPDPData[index].current;
-  for (int i = 0; i < kNumPDPChannels; i++) {
-    data[i] = currents[i];
-  }
-}
-
-#define REGISTER(NAME) \
-  SimPDPData[index].NAME.RegisterCallback(callback, param, initialNotify)
-
-void HALSIM_RegisterPDPAllNonCurrentCallbacks(int32_t index, int32_t channel,
-                                              HAL_NotifyCallback callback,
-                                              void* param,
-                                              HAL_Bool initialNotify) {
-  REGISTER(initialized);
-  REGISTER(temperature);
-  REGISTER(voltage);
-}
-}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/PDPDataInternal.h b/hal/src/main/native/sim/mockdata/PDPDataInternal.h
deleted file mode 100644
index 3392eaa..0000000
--- a/hal/src/main/native/sim/mockdata/PDPDataInternal.h
+++ /dev/null
@@ -1,36 +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 "../PortsInternal.h"
-#include "hal/simulation/PDPData.h"
-#include "hal/simulation/SimDataValue.h"
-
-namespace hal {
-class PDPData {
-  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
-  HAL_SIMDATAVALUE_DEFINE_NAME(Temperature)
-  HAL_SIMDATAVALUE_DEFINE_NAME(Voltage)
-  HAL_SIMDATAVALUE_DEFINE_NAME(Current)
-
-  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr double GetCurrentDefault() {
-    return 0.0;
-  }
-
- public:
-  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
-      false};
-  SimDataValue<double, HAL_MakeDouble, GetTemperatureName> temperature{0.0};
-  SimDataValue<double, HAL_MakeDouble, GetVoltageName> voltage{12.0};
-  SimDataValue<double, HAL_MakeDouble, GetCurrentName, GetCurrentDefault>
-      current[kNumPDPChannels];
-
-  virtual void ResetData();
-};
-extern PDPData* SimPDPData;
-}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/PWMData.cpp b/hal/src/main/native/sim/mockdata/PWMData.cpp
index 4d2121d..a221d13 100644
--- a/hal/src/main/native/sim/mockdata/PWMData.cpp
+++ b/hal/src/main/native/sim/mockdata/PWMData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "PWMDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializePWMData() {
   static PWMData spd[kNumPWMChannels];
   ::hal::SimPWMData = spd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 PWMData* hal::SimPWMData;
 void PWMData::ResetData() {
@@ -30,7 +25,9 @@
 }
 
 extern "C" {
-void HALSIM_ResetPWMData(int32_t index) { SimPWMData[index].ResetData(); }
+void HALSIM_ResetPWMData(int32_t index) {
+  SimPWMData[index].ResetData();
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
   HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PWM##CAPINAME, SimPWMData, \
diff --git a/hal/src/main/native/sim/mockdata/PWMDataInternal.h b/hal/src/main/native/sim/mockdata/PWMDataInternal.h
index 028e25a..737ced6 100644
--- a/hal/src/main/native/sim/mockdata/PWMDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/PWMDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/PowerDistributionData.cpp b/hal/src/main/native/sim/mockdata/PowerDistributionData.cpp
new file mode 100644
index 0000000..9c5b826
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/PowerDistributionData.cpp
@@ -0,0 +1,72 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "../PortsInternal.h"
+#include "PowerDistributionDataInternal.h"
+
+using namespace hal;
+
+namespace hal::init {
+void InitializePowerDistributionData() {
+  static PowerDistributionData spd[kNumPDSimModules];
+  ::hal::SimPowerDistributionData = spd;
+}
+}  // namespace hal::init
+
+PowerDistributionData* hal::SimPowerDistributionData;
+void PowerDistributionData::ResetData() {
+  initialized.Reset(false);
+  temperature.Reset(0.0);
+  voltage.Reset(12.0);
+  for (int i = 0; i < kNumPDSimChannels; i++) {
+    current[i].Reset(0.0);
+  }
+}
+
+extern "C" {
+void HALSIM_ResetPowerDistributionData(int32_t index) {
+  SimPowerDistributionData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                            \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, PowerDistribution##CAPINAME, \
+                               SimPowerDistributionData, LOWERNAME)
+
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(double, Temperature, temperature)
+DEFINE_CAPI(double, Voltage, voltage)
+HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(double, HALSIM, PowerDistributionCurrent,
+                                     SimPowerDistributionData, current)
+
+void HALSIM_GetPowerDistributionAllCurrents(int32_t index, double* currents,
+                                            int length) {
+  auto& data = SimPowerDistributionData[index].current;
+  int toCopy = (std::min)(length, kNumPDSimChannels);
+  for (int i = 0; i < toCopy; i++) {
+    currents[i] = data[i];
+  }
+}
+
+void HALSIM_SetPowerDistributionAllCurrents(int32_t index,
+                                            const double* currents,
+                                            int length) {
+  auto& data = SimPowerDistributionData[index].current;
+  int toCopy = (std::min)(length, kNumPDSimChannels);
+  for (int i = 0; i < toCopy; i++) {
+    data[i] = currents[i];
+  }
+}
+
+#define REGISTER(NAME)                                                   \
+  SimPowerDistributionData[index].NAME.RegisterCallback(callback, param, \
+                                                        initialNotify)
+
+void HALSIM_RegisterPowerDistributionAllNonCurrentCallbacks(
+    int32_t index, int32_t channel, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(temperature);
+  REGISTER(voltage);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/PowerDistributionDataInternal.h b/hal/src/main/native/sim/mockdata/PowerDistributionDataInternal.h
new file mode 100644
index 0000000..4876dbd
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/PowerDistributionDataInternal.h
@@ -0,0 +1,36 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 "../PortsInternal.h"
+#include "hal/simulation/PowerDistributionData.h"
+#include "hal/simulation/SimDataValue.h"
+
+namespace hal {
+constexpr int32_t kNumPDSimModules = hal::kNumREVPDHModules;
+constexpr int32_t kNumPDSimChannels = hal::kNumREVPDHChannels;
+
+class PowerDistributionData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Temperature)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Voltage)
+  HAL_SIMDATAVALUE_DEFINE_NAME(Current)
+
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr double GetCurrentDefault() {
+    return 0.0;
+  }
+
+ public:
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
+  SimDataValue<double, HAL_MakeDouble, GetTemperatureName> temperature{0.0};
+  SimDataValue<double, HAL_MakeDouble, GetVoltageName> voltage{12.0};
+  SimDataValue<double, HAL_MakeDouble, GetCurrentName, GetCurrentDefault>
+      current[kNumPDSimChannels];
+
+  virtual void ResetData();
+};
+extern PowerDistributionData* SimPowerDistributionData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/REVPHData.cpp b/hal/src/main/native/sim/mockdata/REVPHData.cpp
new file mode 100644
index 0000000..6c0ed5a
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/REVPHData.cpp
@@ -0,0 +1,83 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "../PortsInternal.h"
+#include "REVPHDataInternal.h"
+
+using namespace hal;
+
+namespace hal::init {
+void InitializeREVPHData() {
+  static REVPHData spd[kNumREVPHModules];
+  ::hal::SimREVPHData = spd;
+}
+}  // namespace hal::init
+
+REVPHData* hal::SimREVPHData;
+void REVPHData::ResetData() {
+  for (int i = 0; i < kNumREVPHChannels; i++) {
+    solenoidOutput[i].Reset(false);
+  }
+  initialized.Reset(false);
+  compressorOn.Reset(false);
+  closedLoopEnabled.Reset(true);
+  pressureSwitch.Reset(false);
+  compressorCurrent.Reset(0.0);
+}
+
+extern "C" {
+void HALSIM_ResetREVPHData(int32_t index) {
+  SimREVPHData[index].ResetData();
+}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                              \
+  HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, REVPH##CAPINAME, SimREVPHData, \
+                               LOWERNAME)
+
+HAL_SIMDATAVALUE_DEFINE_CAPI_CHANNEL(HAL_Bool, HALSIM, REVPHSolenoidOutput,
+                                     SimREVPHData, solenoidOutput)
+DEFINE_CAPI(HAL_Bool, Initialized, initialized)
+DEFINE_CAPI(HAL_Bool, CompressorOn, compressorOn)
+DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, closedLoopEnabled)
+DEFINE_CAPI(HAL_Bool, PressureSwitch, pressureSwitch)
+DEFINE_CAPI(double, CompressorCurrent, compressorCurrent)
+
+void HALSIM_GetREVPHAllSolenoids(int32_t index, uint8_t* values) {
+  auto& data = SimREVPHData[index].solenoidOutput;
+  uint8_t ret = 0;
+  for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
+    ret |= (data[i] << i);
+  }
+  *values = ret;
+}
+
+void HALSIM_SetREVPHAllSolenoids(int32_t index, uint8_t values) {
+  auto& data = SimREVPHData[index].solenoidOutput;
+  for (int i = 0; i < kNumCTRESolenoidChannels; i++) {
+    data[i] = (values & 0x1) != 0;
+    values >>= 1;
+  }
+}
+
+#define REGISTER(NAME) \
+  SimREVPHData[index].NAME.RegisterCallback(callback, param, initialNotify)
+
+void HALSIM_RegisterREVPHAllNonSolenoidCallbacks(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify) {
+  REGISTER(initialized);
+  REGISTER(compressorOn);
+  REGISTER(closedLoopEnabled);
+  REGISTER(pressureSwitch);
+  REGISTER(compressorCurrent);
+}
+
+void HALSIM_RegisterREVPHAllSolenoidCallbacks(int32_t index, int32_t channel,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify) {
+  REGISTER(solenoidOutput[channel]);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/REVPHDataInternal.h b/hal/src/main/native/sim/mockdata/REVPHDataInternal.h
new file mode 100644
index 0000000..ebf4964
--- /dev/null
+++ b/hal/src/main/native/sim/mockdata/REVPHDataInternal.h
@@ -0,0 +1,43 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 "../PortsInternal.h"
+#include "hal/simulation/REVPHData.h"
+#include "hal/simulation/SimDataValue.h"
+
+namespace hal {
+class REVPHData {
+  HAL_SIMDATAVALUE_DEFINE_NAME(Initialized)
+  HAL_SIMDATAVALUE_DEFINE_NAME(SolenoidOutput)
+  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorOn)
+  HAL_SIMDATAVALUE_DEFINE_NAME(ClosedLoopEnabled)
+  HAL_SIMDATAVALUE_DEFINE_NAME(PressureSwitch)
+  HAL_SIMDATAVALUE_DEFINE_NAME(CompressorCurrent)
+
+  static LLVM_ATTRIBUTE_ALWAYS_INLINE constexpr HAL_Bool
+  GetSolenoidOutputDefault() {
+    return false;
+  }
+
+ public:
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetInitializedName> initialized{
+      false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetSolenoidOutputName,
+               GetSolenoidOutputDefault>
+      solenoidOutput[kNumREVPHChannels];
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetCompressorOnName> compressorOn{
+      false};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetClosedLoopEnabledName>
+      closedLoopEnabled{true};
+  SimDataValue<HAL_Bool, HAL_MakeBoolean, GetPressureSwitchName> pressureSwitch{
+      false};
+  SimDataValue<double, HAL_MakeDouble, GetCompressorCurrentName>
+      compressorCurrent{0.0};
+
+  virtual void ResetData();
+};
+extern REVPHData* SimREVPHData;
+}  // namespace hal
diff --git a/hal/src/main/native/sim/mockdata/RelayData.cpp b/hal/src/main/native/sim/mockdata/RelayData.cpp
index 4623203..ffe3bd5 100644
--- a/hal/src/main/native/sim/mockdata/RelayData.cpp
+++ b/hal/src/main/native/sim/mockdata/RelayData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "RelayDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeRelayData() {
   static RelayData srd[kNumRelayHeaders];
   ::hal::SimRelayData = srd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 RelayData* hal::SimRelayData;
 void RelayData::ResetData() {
@@ -28,7 +23,9 @@
 }
 
 extern "C" {
-void HALSIM_ResetRelayData(int32_t index) { SimRelayData[index].ResetData(); }
+void HALSIM_ResetRelayData(int32_t index) {
+  SimRelayData[index].ResetData();
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                              \
   HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, Relay##CAPINAME, SimRelayData, \
diff --git a/hal/src/main/native/sim/mockdata/RelayDataInternal.h b/hal/src/main/native/sim/mockdata/RelayDataInternal.h
index d62ea2f..b6fec87 100644
--- a/hal/src/main/native/sim/mockdata/RelayDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/RelayDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/RoboRioData.cpp b/hal/src/main/native/sim/mockdata/RoboRioData.cpp
index 76406f5..6932620 100644
--- a/hal/src/main/native/sim/mockdata/RoboRioData.cpp
+++ b/hal/src/main/native/sim/mockdata/RoboRioData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "RoboRioDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeRoboRioData() {
   static RoboRioData srrd;
   ::hal::SimRoboRioData = &srrd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 RoboRioData* hal::SimRoboRioData;
 void RoboRioData::ResetData() {
@@ -36,10 +31,13 @@
   userFaults6V.Reset(0);
   userFaults5V.Reset(0);
   userFaults3V3.Reset(0);
+  brownoutVoltage.Reset(6.75);
 }
 
 extern "C" {
-void HALSIM_ResetRoboRioData(void) { SimRoboRioData->ResetData(); }
+void HALSIM_ResetRoboRioData(void) {
+  SimRoboRioData->ResetData();
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
   HAL_SIMDATAVALUE_DEFINE_CAPI_NOINDEX(TYPE, HALSIM, RoboRio##CAPINAME, \
@@ -60,6 +58,7 @@
 DEFINE_CAPI(int32_t, UserFaults6V, userFaults6V)
 DEFINE_CAPI(int32_t, UserFaults5V, userFaults5V)
 DEFINE_CAPI(int32_t, UserFaults3V3, userFaults3V3)
+DEFINE_CAPI(double, BrownoutVoltage, brownoutVoltage)
 
 #define REGISTER(NAME) \
   SimRoboRioData->NAME.RegisterCallback(callback, param, initialNotify)
@@ -81,5 +80,6 @@
   REGISTER(userFaults6V);
   REGISTER(userFaults5V);
   REGISTER(userFaults3V3);
+  REGISTER(brownoutVoltage);
 }
 }  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h
index 2fb3456..99e61ea 100644
--- a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.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
 
@@ -27,6 +24,7 @@
   HAL_SIMDATAVALUE_DEFINE_NAME(UserFaults6V)
   HAL_SIMDATAVALUE_DEFINE_NAME(UserFaults5V)
   HAL_SIMDATAVALUE_DEFINE_NAME(UserFaults3V3)
+  HAL_SIMDATAVALUE_DEFINE_NAME(BrownoutVoltage)
 
  public:
   SimDataValue<HAL_Bool, HAL_MakeBoolean, GetFPGAButtonName> fpgaButton{false};
@@ -49,6 +47,8 @@
   SimDataValue<int32_t, HAL_MakeInt, GetUserFaults6VName> userFaults6V{0};
   SimDataValue<int32_t, HAL_MakeInt, GetUserFaults5VName> userFaults5V{0};
   SimDataValue<int32_t, HAL_MakeInt, GetUserFaults3V3Name> userFaults3V3{0};
+  SimDataValue<double, HAL_MakeDouble, GetBrownoutVoltageName> brownoutVoltage{
+      6.75};
 
   virtual void ResetData();
 };
diff --git a/hal/src/main/native/sim/mockdata/SPIAccelerometerData.cpp b/hal/src/main/native/sim/mockdata/SPIAccelerometerData.cpp
index db7dc1d..6c5f341 100644
--- a/hal/src/main/native/sim/mockdata/SPIAccelerometerData.cpp
+++ b/hal/src/main/native/sim/mockdata/SPIAccelerometerData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "SPIAccelerometerDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeSPIAccelerometerData() {
   static SPIAccelerometerData ssad[5];
   ::hal::SimSPIAccelerometerData = ssad;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 SPIAccelerometerData* hal::SimSPIAccelerometerData;
 void SPIAccelerometerData::ResetData() {
diff --git a/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h b/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h
index 59c6685..db405f8 100644
--- a/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/SPIAccelerometerDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/SPIData.cpp b/hal/src/main/native/sim/mockdata/SPIData.cpp
index 106ab7f..9499b9b 100644
--- a/hal/src/main/native/sim/mockdata/SPIData.cpp
+++ b/hal/src/main/native/sim/mockdata/SPIData.cpp
@@ -1,23 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "../PortsInternal.h"
 #include "SPIDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeSPIData() {
   static SPIData ssd[5];
   ::hal::SimSPIData = ssd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 SPIData* hal::SimSPIData;
 void SPIData::ResetData() {
@@ -52,7 +47,9 @@
 }
 
 extern "C" {
-void HALSIM_ResetSPIData(int32_t index) { SimSPIData[index].ResetData(); }
+void HALSIM_ResetSPIData(int32_t index) {
+  SimSPIData[index].ResetData();
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, LOWERNAME)                          \
   HAL_SIMDATAVALUE_DEFINE_CAPI(TYPE, HALSIM, SPI##CAPINAME, SimSPIData, \
diff --git a/hal/src/main/native/sim/mockdata/SPIDataInternal.h b/hal/src/main/native/sim/mockdata/SPIDataInternal.h
index ff0a6c9..eb5a5a7 100644
--- a/hal/src/main/native/sim/mockdata/SPIDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/SPIDataInternal.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
 
diff --git a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp
index 6c0a7f2..9c7fdbc 100644
--- a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp
+++ b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp
@@ -1,50 +1,55 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #include "hal/simulation/SimDeviceData.h"  // NOLINT(build/include_order)
 
 #include <algorithm>
 
+#include <wpi/StringExtras.h>
+
 #include "SimDeviceDataInternal.h"
 
 using namespace hal;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeSimDeviceData() {
   static SimDeviceData sdd;
   ::hal::SimSimDeviceData = &sdd;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 SimDeviceData* hal::SimSimDeviceData;
 
 SimDeviceData::Device* SimDeviceData::LookupDevice(HAL_SimDeviceHandle handle) {
-  if (handle <= 0) return nullptr;
-  --handle;
-  if (static_cast<uint32_t>(handle) >= m_devices.size() || !m_devices[handle])
+  if (handle <= 0) {
     return nullptr;
+  }
+  --handle;
+  if (static_cast<uint32_t>(handle) >= m_devices.size() || !m_devices[handle]) {
+    return nullptr;
+  }
   return m_devices[handle].get();
 }
 
 SimDeviceData::Value* SimDeviceData::LookupValue(HAL_SimValueHandle handle) {
-  if (handle <= 0) return nullptr;
+  if (handle <= 0) {
+    return nullptr;
+  }
 
   // look up device
   Device* deviceImpl = LookupDevice(handle >> 16);
-  if (!deviceImpl) return nullptr;
+  if (!deviceImpl) {
+    return nullptr;
+  }
 
   // look up value
   handle &= 0xffff;
   --handle;
   if (static_cast<uint32_t>(handle) >= deviceImpl->values.size() ||
-      !deviceImpl->values[handle])
+      !deviceImpl->values[handle]) {
     return nullptr;
+  }
 
   return deviceImpl->values[handle].get();
 }
@@ -68,7 +73,9 @@
 bool SimDeviceData::IsDeviceEnabled(const char* name) {
   std::scoped_lock lock(m_mutex);
   for (const auto& elem : m_prefixEnabled) {
-    if (wpi::StringRef{name}.startswith(elem.first)) return elem.second;
+    if (wpi::starts_with(name, elem.first)) {
+      return elem.second;
+    }
   }
   return true;
 }
@@ -78,18 +85,24 @@
 
   // don't create if disabled
   for (const auto& elem : m_prefixEnabled) {
-    if (wpi::StringRef{name}.startswith(elem.first)) {
-      if (elem.second) break;  // enabled
-      return 0;                // disabled
+    if (wpi::starts_with(name, elem.first)) {
+      if (elem.second) {
+        break;  // enabled
+      }
+      return 0;  // disabled
     }
   }
 
   // check for duplicates and don't overwrite them
-  if (m_deviceMap.count(name) > 0) return 0;
+  if (m_deviceMap.count(name) > 0) {
+    return 0;
+  }
 
   // don't allow more than 4096 devices (limit driven by 12-bit allocation in
   // value changed callback uid)
-  if (m_devices.size() >= 4095) return 0;
+  if (m_devices.size() >= 4095) {
+    return 0;
+  }
 
   // create and save
   auto deviceImpl = std::make_shared<Device>(name);
@@ -108,9 +121,13 @@
   --handle;
 
   // see if it exists
-  if (handle < 0 || static_cast<uint32_t>(handle) >= m_devices.size()) return;
+  if (handle < 0 || static_cast<uint32_t>(handle) >= m_devices.size()) {
+    return;
+  }
   auto deviceImpl = std::move(m_devices[handle]);
-  if (!deviceImpl) return;
+  if (!deviceImpl) {
+    return;
+  }
 
   // remove from map
   m_deviceMap.erase(deviceImpl->name);
@@ -122,27 +139,32 @@
   m_deviceFreed(deviceImpl->name.c_str(), handle + 1);
 }
 
-HAL_SimValueHandle SimDeviceData::CreateValue(HAL_SimDeviceHandle device,
-                                              const char* name, bool readonly,
-                                              int32_t numOptions,
-                                              const char** options,
-                                              const HAL_Value& initialValue) {
+HAL_SimValueHandle SimDeviceData::CreateValue(
+    HAL_SimDeviceHandle device, const char* name, int32_t direction,
+    int32_t numOptions, const char** options, const double* optionValues,
+    const HAL_Value& initialValue) {
   std::scoped_lock lock(m_mutex);
 
   // look up device
   Device* deviceImpl = LookupDevice(device);
-  if (!deviceImpl) return 0;
+  if (!deviceImpl) {
+    return 0;
+  }
 
   // check for duplicates and don't overwrite them
   auto it = deviceImpl->valueMap.find(name);
-  if (it != deviceImpl->valueMap.end()) return 0;
+  if (it != deviceImpl->valueMap.end()) {
+    return 0;
+  }
 
   // don't allow more than 4096 values per device (limit driven by 12-bit
   // allocation in value changed callback uid)
-  if (deviceImpl->values.size() >= 4095) return 0;
+  if (deviceImpl->values.size() >= 4095) {
+    return 0;
+  }
 
   // create and save; encode device into handle
-  auto valueImplPtr = std::make_unique<Value>(name, readonly, initialValue);
+  auto valueImplPtr = std::make_unique<Value>(name, direction, initialValue);
   Value* valueImpl = valueImplPtr.get();
   HAL_SimValueHandle valueHandle =
       (device << 16) |
@@ -159,10 +181,14 @@
           valueImpl->enumOptions.back().c_str());
     }
   }
+  // copy option values (if any provided)
+  if (numOptions > 0 && optionValues) {
+    valueImpl->enumOptionValues.assign(optionValues, optionValues + numOptions);
+  }
   deviceImpl->valueMap[name] = valueImpl;
 
   // notify callbacks
-  deviceImpl->valueCreated(name, valueHandle, readonly, &initialValue);
+  deviceImpl->valueCreated(name, valueHandle, direction, &initialValue);
 
   return valueHandle;
 }
@@ -185,13 +211,56 @@
                              const HAL_Value& value) {
   std::scoped_lock lock(m_mutex);
   Value* valueImpl = LookupValue(handle);
-  if (!valueImpl) return;
+  if (!valueImpl) {
+    return;
+  }
 
   valueImpl->value = value;
 
   // notify callbacks
   valueImpl->changed(valueImpl->name.c_str(), valueImpl->handle,
-                     valueImpl->readonly, &value);
+                     valueImpl->direction, &value);
+}
+
+void SimDeviceData::ResetValue(HAL_SimValueHandle handle) {
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(handle);
+  if (!valueImpl) {
+    return;
+  }
+
+  // don't notify reset if we aren't going to actually reset anything
+  switch (valueImpl->value.type) {
+    case HAL_INT:
+    case HAL_LONG:
+    case HAL_DOUBLE:
+      break;
+    default:
+      return;
+  }
+
+  // notify reset callbacks (done here so they're called with the old value)
+  valueImpl->reset(valueImpl->name.c_str(), valueImpl->handle,
+                   valueImpl->direction, &valueImpl->value);
+
+  // set user-facing value to 0
+  switch (valueImpl->value.type) {
+    case HAL_INT:
+      valueImpl->value.data.v_int = 0;
+      break;
+    case HAL_LONG:
+      valueImpl->value.data.v_long = 0;
+      break;
+    case HAL_DOUBLE:
+      valueImpl->value.data.v_double = 0;
+      break;
+    default:
+      return;
+  }
+
+  // notify changed callbacks
+  valueImpl->changed(valueImpl->name.c_str(), valueImpl->handle,
+                     valueImpl->direction, &valueImpl->value);
 }
 
 int32_t SimDeviceData::RegisterDeviceCreatedCallback(
@@ -204,15 +273,20 @@
 
   // initial notifications
   if (initialNotify) {
-    for (auto&& device : m_devices)
-      callback(device->name.c_str(), param, device->handle);
+    for (auto&& device : m_devices) {
+      if (wpi::starts_with(device->name, prefix)) {
+        callback(device->name.c_str(), param, device->handle);
+      }
+    }
   }
 
   return index;
 }
 
 void SimDeviceData::CancelDeviceCreatedCallback(int32_t uid) {
-  if (uid <= 0) return;
+  if (uid <= 0) {
+    return;
+  }
   std::scoped_lock lock(m_mutex);
   m_deviceCreated.Cancel(uid);
 }
@@ -224,7 +298,9 @@
 }
 
 void SimDeviceData::CancelDeviceFreedCallback(int32_t uid) {
-  if (uid <= 0) return;
+  if (uid <= 0) {
+    return;
+  }
   std::scoped_lock lock(m_mutex);
   m_deviceFreed.Cancel(uid);
 }
@@ -232,11 +308,14 @@
 HAL_SimDeviceHandle SimDeviceData::GetDeviceHandle(const char* name) {
   std::scoped_lock lock(m_mutex);
   auto it = m_deviceMap.find(name);
-  if (it == m_deviceMap.end()) return 0;
-  if (auto deviceImpl = it->getValue().lock())
-    return deviceImpl->handle;
-  else
+  if (it == m_deviceMap.end()) {
     return 0;
+  }
+  if (auto deviceImpl = it->getValue().lock()) {
+    return deviceImpl->handle;
+  } else {
+    return 0;
+  }
 }
 
 const char* SimDeviceData::GetDeviceName(HAL_SimDeviceHandle handle) {
@@ -244,7 +323,9 @@
 
   // look up device
   Device* deviceImpl = LookupDevice(handle);
-  if (!deviceImpl) return nullptr;
+  if (!deviceImpl) {
+    return nullptr;
+  }
 
   return deviceImpl->name.c_str();
 }
@@ -253,8 +334,9 @@
                                      HALSIM_SimDeviceCallback callback) {
   std::scoped_lock lock(m_mutex);
   for (auto&& device : m_devices) {
-    if (wpi::StringRef{device->name}.startswith(prefix))
+    if (wpi::starts_with(device->name, prefix)) {
       callback(device->name.c_str(), param, device->handle);
+    }
   }
 }
 
@@ -263,16 +345,19 @@
     bool initialNotify) {
   std::scoped_lock lock(m_mutex);
   Device* deviceImpl = LookupDevice(device);
-  if (!deviceImpl) return -1;
+  if (!deviceImpl) {
+    return -1;
+  }
 
   // register callback
   int32_t index = deviceImpl->valueCreated.Register(callback, param);
 
   // initial notifications
   if (initialNotify) {
-    for (auto&& value : deviceImpl->values)
-      callback(value->name.c_str(), param, value->handle, value->readonly,
+    for (auto&& value : deviceImpl->values) {
+      callback(value->name.c_str(), param, value->handle, value->direction,
                &value->value);
+    }
   }
 
   // encode device into uid
@@ -280,10 +365,14 @@
 }
 
 void SimDeviceData::CancelValueCreatedCallback(int32_t uid) {
-  if (uid <= 0) return;
+  if (uid <= 0) {
+    return;
+  }
   std::scoped_lock lock(m_mutex);
   Device* deviceImpl = LookupDevice(uid >> 16);
-  if (!deviceImpl) return;
+  if (!deviceImpl) {
+    return;
+  }
   deviceImpl->valueCreated.Cancel(uid & 0xffff);
 }
 
@@ -292,15 +381,18 @@
     bool initialNotify) {
   std::scoped_lock lock(m_mutex);
   Value* valueImpl = LookupValue(handle);
-  if (!valueImpl) return -1;
+  if (!valueImpl) {
+    return -1;
+  }
 
   // register callback
   int32_t index = valueImpl->changed.Register(callback, param);
 
   // initial notification
-  if (initialNotify)
+  if (initialNotify) {
     callback(valueImpl->name.c_str(), param, valueImpl->handle,
-             valueImpl->readonly, &valueImpl->value);
+             valueImpl->direction, &valueImpl->value);
+  }
 
   // encode device and value into uid
   return (((handle >> 16) & 0xfff) << 19) | ((handle & 0xfff) << 7) |
@@ -308,23 +400,62 @@
 }
 
 void SimDeviceData::CancelValueChangedCallback(int32_t uid) {
-  if (uid <= 0) return;
+  if (uid <= 0) {
+    return;
+  }
   std::scoped_lock lock(m_mutex);
   Value* valueImpl = LookupValue(((uid >> 19) << 16) | ((uid >> 7) & 0xfff));
-  if (!valueImpl) return;
+  if (!valueImpl) {
+    return;
+  }
   valueImpl->changed.Cancel(uid & 0x7f);
 }
 
+int32_t SimDeviceData::RegisterValueResetCallback(
+    HAL_SimValueHandle handle, void* param, HALSIM_SimValueCallback callback,
+    bool initialNotify) {
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(handle);
+  if (!valueImpl) {
+    return -1;
+  }
+
+  // register callback
+  int32_t index = valueImpl->reset.Register(callback, param);
+
+  // encode device and value into uid
+  return (((handle >> 16) & 0xfff) << 19) | ((handle & 0xfff) << 7) |
+         (index & 0x7f);
+}
+
+void SimDeviceData::CancelValueResetCallback(int32_t uid) {
+  if (uid <= 0) {
+    return;
+  }
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(((uid >> 19) << 16) | ((uid >> 7) & 0xfff));
+  if (!valueImpl) {
+    return;
+  }
+  valueImpl->reset.Cancel(uid & 0x7f);
+}
+
 HAL_SimValueHandle SimDeviceData::GetValueHandle(HAL_SimDeviceHandle device,
                                                  const char* name) {
   std::scoped_lock lock(m_mutex);
   Device* deviceImpl = LookupDevice(device);
-  if (!deviceImpl) return 0;
+  if (!deviceImpl) {
+    return 0;
+  }
 
   // lookup value
   auto it = deviceImpl->valueMap.find(name);
-  if (it == deviceImpl->valueMap.end()) return 0;
-  if (!it->getValue()) return 0;
+  if (it == deviceImpl->valueMap.end()) {
+    return 0;
+  }
+  if (!it->getValue()) {
+    return 0;
+  }
   return it->getValue()->handle;
 }
 
@@ -332,11 +463,14 @@
                                     HALSIM_SimValueCallback callback) {
   std::scoped_lock lock(m_mutex);
   Device* deviceImpl = LookupDevice(device);
-  if (!deviceImpl) return;
+  if (!deviceImpl) {
+    return;
+  }
 
-  for (auto&& value : deviceImpl->values)
-    callback(value->name.c_str(), param, value->handle, value->readonly,
+  for (auto&& value : deviceImpl->values) {
+    callback(value->name.c_str(), param, value->handle, value->direction,
              &value->value);
+  }
 }
 
 const char** SimDeviceData::GetValueEnumOptions(HAL_SimValueHandle handle,
@@ -345,7 +479,9 @@
 
   std::scoped_lock lock(m_mutex);
   Value* valueImpl = LookupValue(handle);
-  if (!valueImpl) return nullptr;
+  if (!valueImpl) {
+    return nullptr;
+  }
 
   // get list of options (safe to return as they never change)
   auto& options = valueImpl->cstrEnumOptions;
@@ -353,6 +489,22 @@
   return options.data();
 }
 
+const double* SimDeviceData::GetValueEnumDoubleValues(HAL_SimValueHandle handle,
+                                                      int32_t* numOptions) {
+  *numOptions = 0;
+
+  std::scoped_lock lock(m_mutex);
+  Value* valueImpl = LookupValue(handle);
+  if (!valueImpl) {
+    return nullptr;
+  }
+
+  // get list of option values (safe to return as they never change)
+  auto& optionValues = valueImpl->enumOptionValues;
+  *numOptions = optionValues.size();
+  return optionValues.data();
+}
+
 void SimDeviceData::ResetData() {
   std::scoped_lock lock(m_mutex);
   m_devices.clear();
@@ -383,8 +535,9 @@
   SimSimDeviceData->CancelDeviceCreatedCallback(uid);
 }
 
-int32_t HALSIM_RegisterSimDeviceFreedCallback(
-    const char* prefix, void* param, HALSIM_SimDeviceCallback callback) {
+int32_t HALSIM_RegisterSimDeviceFreedCallback(const char* prefix, void* param,
+                                              HALSIM_SimDeviceCallback callback,
+                                              HAL_Bool initialNotify) {
   return SimSimDeviceData->RegisterDeviceFreedCallback(prefix, param, callback);
 }
 
@@ -401,7 +554,9 @@
 }
 
 HAL_SimDeviceHandle HALSIM_GetSimValueDeviceHandle(HAL_SimValueHandle handle) {
-  if (handle <= 0) return 0;
+  if (handle <= 0) {
+    return 0;
+  }
   return handle >> 16;
 }
 
@@ -434,6 +589,18 @@
   SimSimDeviceData->CancelValueChangedCallback(uid);
 }
 
+int32_t HALSIM_RegisterSimValueResetCallback(HAL_SimValueHandle handle,
+                                             void* param,
+                                             HALSIM_SimValueCallback callback,
+                                             HAL_Bool initialNotify) {
+  return SimSimDeviceData->RegisterValueResetCallback(handle, param, callback,
+                                                      initialNotify);
+}
+
+void HALSIM_CancelSimValueResetCallback(int32_t uid) {
+  SimSimDeviceData->CancelValueResetCallback(uid);
+}
+
 HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device,
                                             const char* name) {
   return SimSimDeviceData->GetValueHandle(device, name);
@@ -449,6 +616,13 @@
   return SimSimDeviceData->GetValueEnumOptions(handle, numOptions);
 }
 
-void HALSIM_ResetSimDeviceData(void) { SimSimDeviceData->ResetData(); }
+const double* HALSIM_GetSimValueEnumDoubleValues(HAL_SimValueHandle handle,
+                                                 int32_t* numOptions) {
+  return SimSimDeviceData->GetValueEnumDoubleValues(handle, numOptions);
+}
+
+void HALSIM_ResetSimDeviceData(void) {
+  SimSimDeviceData->ResetData();
+}
 
 }  // extern "C"
diff --git a/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h b/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h
index 63c2288..deff6ed 100644
--- a/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h
+++ b/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.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,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include <wpi/StringExtras.h>
 #include <wpi/StringMap.h>
 #include <wpi/UidVector.h>
 #include <wpi/spinlock.h>
@@ -36,17 +34,25 @@
 
  public:
   void Cancel(int32_t uid) {
-    if (m_callbacks) m_callbacks->erase(uid - 1);
+    if (m_callbacks) {
+      m_callbacks->erase(uid - 1);
+    }
   }
 
   void Reset() {
-    if (m_callbacks) m_callbacks->clear();
+    if (m_callbacks) {
+      m_callbacks->clear();
+    }
   }
 
   int32_t Register(CallbackFunction callback, void* param) {
     // Must return -1 on a null callback for error handling
-    if (callback == nullptr) return -1;
-    if (!m_callbacks) m_callbacks = std::make_unique<CallbackVector>();
+    if (callback == nullptr) {
+      return -1;
+    }
+    if (!m_callbacks) {
+      m_callbacks = std::make_unique<CallbackVector>();
+    }
     return m_callbacks->emplace_back(param,
                                      reinterpret_cast<RawFunctor>(callback)) +
            1;
@@ -87,17 +93,25 @@
 
  public:
   void Cancel(int32_t uid) {
-    if (m_callbacks) m_callbacks->erase(uid - 1);
+    if (m_callbacks) {
+      m_callbacks->erase(uid - 1);
+    }
   }
 
   void Reset() {
-    if (m_callbacks) m_callbacks->clear();
+    if (m_callbacks) {
+      m_callbacks->clear();
+    }
   }
 
   int32_t Register(const char* prefix, void* param, CallbackFunction callback) {
     // Must return -1 on a null callback for error handling
-    if (callback == nullptr) return -1;
-    if (!m_callbacks) m_callbacks = std::make_unique<CallbackVector>();
+    if (callback == nullptr) {
+      return -1;
+    }
+    if (!m_callbacks) {
+      m_callbacks = std::make_unique<CallbackVector>();
+    }
     return m_callbacks->emplace_back(prefix, param, callback) + 1;
   }
 
@@ -105,7 +119,7 @@
   void Invoke(const char* name, U&&... u) const {
     if (m_callbacks) {
       for (auto&& cb : *m_callbacks) {
-        if (wpi::StringRef{name}.startswith(cb.prefix)) {
+        if (wpi::starts_with(name, cb.prefix)) {
           cb.callback(name, cb.param, std::forward<U>(u)...);
         }
       }
@@ -126,16 +140,18 @@
 class SimDeviceData {
  private:
   struct Value {
-    Value(const char* name_, bool readonly_, const HAL_Value& value_)
-        : name{name_}, readonly{readonly_}, value{value_} {}
+    Value(const char* name_, int32_t direction_, const HAL_Value& value_)
+        : name{name_}, direction{direction_}, value{value_} {}
 
     HAL_SimValueHandle handle{0};
     std::string name;
-    bool readonly;
+    int32_t direction;
     HAL_Value value;
     std::vector<std::string> enumOptions;
     std::vector<const char*> cstrEnumOptions;
+    std::vector<double> enumOptionValues;
     impl::SimUnnamedCallbackRegistry<HALSIM_SimValueCallback> changed;
+    impl::SimUnnamedCallbackRegistry<HALSIM_SimValueCallback> reset;
   };
 
   struct Device {
@@ -168,11 +184,13 @@
   HAL_SimDeviceHandle CreateDevice(const char* name);
   void FreeDevice(HAL_SimDeviceHandle handle);
   HAL_SimValueHandle CreateValue(HAL_SimDeviceHandle device, const char* name,
-                                 bool readonly, int32_t numOptions,
+                                 int32_t direction, int32_t numOptions,
                                  const char** options,
+                                 const double* optionValues,
                                  const HAL_Value& initialValue);
   HAL_Value GetValue(HAL_SimValueHandle handle);
   void SetValue(HAL_SimValueHandle handle, const HAL_Value& value);
+  void ResetValue(HAL_SimValueHandle handle);
 
   int32_t RegisterDeviceCreatedCallback(const char* prefix, void* param,
                                         HALSIM_SimDeviceCallback callback,
@@ -203,6 +221,12 @@
 
   void CancelValueChangedCallback(int32_t uid);
 
+  int32_t RegisterValueResetCallback(HAL_SimValueHandle handle, void* param,
+                                     HALSIM_SimValueCallback callback,
+                                     bool initialNotify);
+
+  void CancelValueResetCallback(int32_t uid);
+
   HAL_SimValueHandle GetValueHandle(HAL_SimDeviceHandle device,
                                     const char* name);
 
@@ -212,6 +236,9 @@
   const char** GetValueEnumOptions(HAL_SimValueHandle handle,
                                    int32_t* numOptions);
 
+  const double* GetValueEnumDoubleValues(HAL_SimValueHandle handle,
+                                         int32_t* numOptions);
+
   void ResetData();
 };
 extern SimDeviceData* SimSimDeviceData;