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/.styleguide b/hal/.styleguide
index 49d4e29..77cd815 100644
--- a/hal/.styleguide
+++ b/hal/.styleguide
@@ -10,6 +10,7 @@
 
 generatedFileExclude {
   hal/src/main/native/athena/ctre/
+  hal/src/main/native/athena/rev/
   hal/src/main/native/athena/frccansae/
   hal/src/main/native/athena/visa/
   hal/src/main/native/include/ctre/
@@ -30,6 +31,7 @@
 includeOtherLibs {
   ^FRC_FPGA_ChipObject/
   ^FRC_NetworkCommunication/
+  ^fmt/
   ^i2clib/
   ^llvm/
   ^opencv2/
diff --git a/hal/CMakeLists.txt b/hal/CMakeLists.txt
index 2e99064..fae74aa 100644
--- a/hal/CMakeLists.txt
+++ b/hal/CMakeLists.txt
@@ -65,8 +65,8 @@
     set (hal_config_dir share/hal)
 endif()
 
-configure_file(hal-config.cmake.in ${CMAKE_BINARY_DIR}/hal-config.cmake )
-install(FILES ${CMAKE_BINARY_DIR}/hal-config.cmake DESTINATION ${hal_config_dir})
+configure_file(hal-config.cmake.in ${WPILIB_BINARY_DIR}/hal-config.cmake )
+install(FILES ${WPILIB_BINARY_DIR}/hal-config.cmake DESTINATION ${hal_config_dir})
 install(EXPORT hal DESTINATION ${hal_config_dir})
 
 # Java bindings
@@ -74,7 +74,7 @@
     find_package(Java REQUIRED)
     find_package(JNI REQUIRED)
     include(UseJava)
-    set(CMAKE_JAVA_COMPILE_FLAGS "-Xlint:unchecked")
+    set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")
 
     configure_file(src/generate/FRCNetComm.java.in FRCNetComm.java)
 
diff --git a/hal/build.gradle b/hal/build.gradle
index e5b5f6c..ed67125 100644
--- a/hal/build.gradle
+++ b/hal/build.gradle
@@ -43,8 +43,6 @@
     }
 }
 
-apply plugin: DisableBuildingGTest
-
 ext {
     addHalDependency = { binary, shared->
         binary.tasks.withType(AbstractNativeSourceCompileTask) {
@@ -129,34 +127,55 @@
     }
 }
 
+Action<List<String>> symbolFilter = { symbols ->
+    symbols.removeIf({ !it.startsWith('HAL_') && !it.startsWith('HALSIM_') })
+} as Action<List<String>>;
+
 nativeUtils.exportsConfigs {
     hal {
-        x86ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
-                            '_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
-                            '_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
-                            '_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
-        x64ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
-                            '_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
-                            '_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
-                            '_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
+        x86ExcludeSymbols = [
+            '_CT??_R0?AV_System_error',
+            '_CT??_R0?AVexception',
+            '_CT??_R0?AVfailure',
+            '_CT??_R0?AVruntime_error',
+            '_CT??_R0?AVsystem_error',
+            '_CTA5?AVfailure',
+            '_TI5?AVfailure',
+            '_CT??_R0?AVout_of_range',
+            '_CTA3?AVout_of_range',
+            '_TI3?AVout_of_range',
+            '_CT??_R0?AVbad_cast'
+        ]
+        x64ExcludeSymbols = [
+            '_CT??_R0?AV_System_error',
+            '_CT??_R0?AVexception',
+            '_CT??_R0?AVfailure',
+            '_CT??_R0?AVruntime_error',
+            '_CT??_R0?AVsystem_error',
+            '_CTA5?AVfailure',
+            '_TI5?AVfailure',
+            '_CT??_R0?AVout_of_range',
+            '_CTA3?AVout_of_range',
+            '_TI3?AVout_of_range',
+            '_CT??_R0?AVbad_cast'
+        ]
     }
     halJNI {
-        x86SymbolFilter = { symbols ->
-            symbols.removeIf({ !it.startsWith('HAL_') && !it.startsWith('HALSIM_') })
-        }
-        x64SymbolFilter = { symbols ->
-            symbols.removeIf({ !it.startsWith('HAL_') && !it.startsWith('HALSIM_') })
-        }
+        x86SymbolFilter = symbolFilter
+        x64SymbolFilter = symbolFilter
     }
 }
 
 model {
     binaries {
         all {
+            it.tasks.withType(AbstractNativeSourceCompileTask) {
+                it.dependsOn generateUsageReporting
+            }
             if (!(it instanceof NativeBinarySpec)) return
-            if (it.component.name != 'hal' && it.component.name != 'halBase') return
-            if (it.targetPlatform.name != nativeUtils.wpi.platforms.roborio) return
-            nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared')
+                if (it.component.name != 'hal' && it.component.name != 'halBase') return
+                if (it.targetPlatform.name != nativeUtils.wpi.platforms.roborio) return
+                nativeUtils.useRequiredLibrary(it, 'ni_link_libraries')
         }
     }
 }
diff --git a/hal/hal-config.cmake.in b/hal/hal-config.cmake.in
index ae5533c..49eac3d 100644
--- a/hal/hal-config.cmake.in
+++ b/hal/hal-config.cmake.in
@@ -2,4 +2,5 @@
 @FILENAME_DEP_REPLACE@
 @WPIUTIL_DEP_REPLACE@
 
+@FILENAME_DEP_REPLACE@
 include(${SELF_DIR}/hal.cmake)
diff --git a/hal/src/dev/java/edu/wpi/first/hal/DevMain.java b/hal/src/dev/java/edu/wpi/first/hal/DevMain.java
index 25c6c90..efe8e9b 100644
--- a/hal/src/dev/java/edu/wpi/first/hal/DevMain.java
+++ b/hal/src/dev/java/edu/wpi/first/hal/DevMain.java
@@ -1,17 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 public final class DevMain {
-  public static void main(String[] args) {
+  public static void main(String[] args) {}
 
-  }
-
-  private DevMain() {
-  }
+  private DevMain() {}
 }
diff --git a/hal/src/dev/native/cpp/main.cpp b/hal/src/dev/native/cpp/main.cpp
index 6bfa3df..721c0f6 100644
--- a/hal/src/dev/native/cpp/main.cpp
+++ b/hal/src/dev/native/cpp/main.cpp
@@ -1,15 +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 <iostream>
+#include <fmt/core.h>
 
 #include "hal/HAL.h"
 
 int main() {
-  std::cout << "Hello World" << std::endl;
-  std::cout << HAL_GetRuntimeType() << std::endl;
+  fmt::print("Hello World\n");
+  fmt::print("{}\n", HAL_GetRuntimeType());
 }
diff --git a/hal/src/generate/FRCNetComm.java.in b/hal/src/generate/FRCNetComm.java.in
index 2c2f924..ce21889 100644
--- a/hal/src/generate/FRCNetComm.java.in
+++ b/hal/src/generate/FRCNetComm.java.in
@@ -12,7 +12,7 @@
   /**
    * Resource type from UsageReporting.
    */
-  @SuppressWarnings({"TypeName", "PMD.ConstantsInInterface"})
+  @SuppressWarnings("TypeName")
   public static final class tResourceType {
     private tResourceType() {
     }
@@ -23,7 +23,7 @@
   /**
    * Instances from UsageReporting.
    */
-  @SuppressWarnings({"TypeName", "PMD.ConstantsInInterface"})
+  @SuppressWarnings("TypeName")
   public static final class tInstances {
     private tInstances() {
     }
diff --git a/hal/src/generate/ResourceType.txt b/hal/src/generate/ResourceType.txt
index 4ee8eb2..f48cb59 100644
--- a/hal/src/generate/ResourceType.txt
+++ b/hal/src/generate/ResourceType.txt
@@ -92,3 +92,4 @@
 kResourceType_DutyCycle = 91
 kResourceType_AddressableLEDs = 92
 kResourceType_FusionVenom = 93
+kResourceType_PS4Controller = 94
diff --git a/hal/src/main/java/edu/wpi/first/hal/AccelerometerJNI.java b/hal/src/main/java/edu/wpi/first/hal/AccelerometerJNI.java
index e1e3750..3f22bcb 100644
--- a/hal/src/main/java/edu/wpi/first/hal/AccelerometerJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/AccelerometerJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/AccumulatorResult.java b/hal/src/main/java/edu/wpi/first/hal/AccumulatorResult.java
index d3aa8c8..9340748 100644
--- a/hal/src/main/java/edu/wpi/first/hal/AccumulatorResult.java
+++ b/hal/src/main/java/edu/wpi/first/hal/AccumulatorResult.java
@@ -1,29 +1,23 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
-/**
- * Structure for holding the values stored in an accumulator.
- */
+/** Structure for holding the values stored in an accumulator. */
 public class AccumulatorResult {
-  /**
-   * The total value accumulated.
-   */
+  /** The total value accumulated. */
   @SuppressWarnings("MemberName")
   public long value;
-  /**
-   * The number of sample value was accumulated over.
-   */
+  /** The number of sample value was accumulated over. */
   @SuppressWarnings("MemberName")
   public long count;
 
   /**
    * Set the value and count.
+   *
+   * @param value The total value accumulated.
+   * @param count The number of samples accumulated.
    */
   public void set(long value, long count) {
     this.value = value;
diff --git a/hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java b/hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java
index fb34996..c732ec6 100644
--- a/hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/AddressableLEDJNI.java
@@ -1,23 +1,25 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 @SuppressWarnings("AbbreviationAsWordInName")
 public class AddressableLEDJNI extends JNIWrapper {
   public static native int initialize(int pwmHandle);
+
   public static native void free(int handle);
 
   public static native void setLength(int handle, int length);
+
   public static native void setData(int handle, byte[] data);
 
-  public static native void setBitTiming(int handle, int lowTime0, int highTime0, int lowTime1, int highTime1);
+  public static native void setBitTiming(
+      int handle, int lowTime0, int highTime0, int lowTime1, int highTime1);
+
   public static native void setSyncTime(int handle, int syncTime);
 
   public static native void start(int handle);
+
   public static native void stop(int handle);
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/AllianceStationID.java b/hal/src/main/java/edu/wpi/first/hal/AllianceStationID.java
index 148dd76..7b601b3 100644
--- a/hal/src/main/java/edu/wpi/first/hal/AllianceStationID.java
+++ b/hal/src/main/java/edu/wpi/first/hal/AllianceStationID.java
@@ -1,12 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 public enum AllianceStationID {
-  Red1, Red2, Red3, Blue1, Blue2, Blue3
+  Red1,
+  Red2,
+  Red3,
+  Blue1,
+  Blue2,
+  Blue3
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/AnalogGyroJNI.java b/hal/src/main/java/edu/wpi/first/hal/AnalogGyroJNI.java
index 332be79..5763f6e 100644
--- a/hal/src/main/java/edu/wpi/first/hal/AnalogGyroJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/AnalogGyroJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -14,12 +11,11 @@
 
   public static native void freeAnalogGyro(int handle);
 
-  public static native void setAnalogGyroParameters(int handle,
-                                                    double voltsPerDegreePerSecond,
-                                                    double offset, int center);
+  public static native void setAnalogGyroParameters(
+      int handle, double voltsPerDegreePerSecond, double offset, int center);
 
-  public static native void setAnalogGyroVoltsPerDegreePerSecond(int handle,
-                                                                 double voltsPerDegreePerSecond);
+  public static native void setAnalogGyroVoltsPerDegreePerSecond(
+      int handle, double voltsPerDegreePerSecond);
 
   public static native void resetAnalogGyro(int handle);
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/AnalogJNI.java b/hal/src/main/java/edu/wpi/first/hal/AnalogJNI.java
index 449c065..e2deadd 100644
--- a/hal/src/main/java/edu/wpi/first/hal/AnalogJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/AnalogJNI.java
@@ -1,32 +1,22 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 public class AnalogJNI extends JNIWrapper {
   /**
-   * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:58</i><br> enum values
+   * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:58</i><br>
+   * enum values
    */
   public interface AnalogTriggerType {
-    /**
-     * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:54</i>
-     */
+    /** <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:54</i> */
     int kInWindow = 0;
-    /**
-     * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:55</i>
-     */
+    /** <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:55</i> */
     int kState = 1;
-    /**
-     * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:56</i>
-     */
+    /** <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:56</i> */
     int kRisingPulse = 2;
-    /**
-     * <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:57</i>
-     */
+    /** <i>native declaration : AthenaJava\target\native\include\HAL\Analog.h:57</i> */
     int kFallingPulse = 3;
   }
 
@@ -68,6 +58,8 @@
 
   public static native int getAnalogVoltsToValue(int analogPortHandle, double voltage);
 
+  public static native double getAnalogValueToVolts(int analogPortHandle, int value);
+
   public static native double getAnalogVoltage(int analogPortHandle);
 
   public static native double getAnalogAverageVoltage(int analogPortHandle);
@@ -98,20 +90,20 @@
 
   public static native void cleanAnalogTrigger(int analogTriggerHandle);
 
-  public static native void setAnalogTriggerLimitsRaw(int analogTriggerHandle, int lower,
-                                                      int upper);
+  public static native void setAnalogTriggerLimitsRaw(
+      int analogTriggerHandle, int lower, int upper);
 
-  public static native void setAnalogTriggerLimitsDutyCycle(int analogTriggerHandle, double lower,
-                                                            double higher);
+  public static native void setAnalogTriggerLimitsDutyCycle(
+      int analogTriggerHandle, double lower, double higher);
 
-  public static native void setAnalogTriggerLimitsVoltage(int analogTriggerHandle,
-                                                          double lower, double upper);
+  public static native void setAnalogTriggerLimitsVoltage(
+      int analogTriggerHandle, double lower, double upper);
 
-  public static native void setAnalogTriggerAveraged(int analogTriggerHandle,
-                                                     boolean useAveragedValue);
+  public static native void setAnalogTriggerAveraged(
+      int analogTriggerHandle, boolean useAveragedValue);
 
-  public static native void setAnalogTriggerFiltered(int analogTriggerHandle,
-                                                     boolean useFilteredValue);
+  public static native void setAnalogTriggerFiltered(
+      int analogTriggerHandle, boolean useFilteredValue);
 
   public static native boolean getAnalogTriggerInWindow(int analogTriggerHandle);
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java b/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java
index 3507569..31cf973 100644
--- a/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
@@ -15,15 +12,15 @@
 
   public static native void writeCANPacket(int handle, byte[] data, int apiId);
 
-  public static native void writeCANPacketRepeating(int handle, byte[] data, int apiId,
-                                                    int repeatMs);
+  public static native void writeCANPacketRepeating(
+      int handle, byte[] data, int apiId, int repeatMs);
 
   public static native void writeCANRTRFrame(int handle, int length, int apiId);
 
   public static native int writeCANPacketNoThrow(int handle, byte[] data, int apiId);
 
-  public static native int writeCANPacketRepeatingNoThrow(int handle, byte[] data, int apiId,
-                                                         int repeatMs);
+  public static native int writeCANPacketRepeatingNoThrow(
+      int handle, byte[] data, int apiId, int repeatMs);
 
   public static native int writeCANRTRFrameNoThrow(int handle, int length, int apiId);
 
@@ -33,6 +30,6 @@
 
   public static native boolean readCANPacketLatest(int handle, int apiId, CANData data);
 
-  public static native boolean readCANPacketTimeout(int handle, int apiId, int timeoutMs,
-                                                 CANData data);
+  public static native boolean readCANPacketTimeout(
+      int handle, int apiId, int timeoutMs, CANData data);
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/CANData.java b/hal/src/main/java/edu/wpi/first/hal/CANData.java
index 23d37c9..94e9f57 100644
--- a/hal/src/main/java/edu/wpi/first/hal/CANData.java
+++ b/hal/src/main/java/edu/wpi/first/hal/CANData.java
@@ -1,22 +1,25 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 public class CANData {
   @SuppressWarnings("MemberName")
   public final byte[] data = new byte[8];
+
   @SuppressWarnings("MemberName")
   public int length;
+
   @SuppressWarnings("MemberName")
   public long timestamp;
 
   /**
    * API used from JNI to set the data.
+   *
+   * @param length Length of packet in bytes.
+   * @param timestamp CAN frame timestamp in microseconds.
+   * @return Buffer containing CAN frame.
    */
   @SuppressWarnings("PMD.MethodReturnsInternalArray")
   public byte[] setData(int length, long timestamp) {
diff --git a/hal/src/main/java/edu/wpi/first/hal/CTREPCMJNI.java b/hal/src/main/java/edu/wpi/first/hal/CTREPCMJNI.java
new file mode 100644
index 0000000..20d5cb8
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/CTREPCMJNI.java
@@ -0,0 +1,52 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class CTREPCMJNI extends JNIWrapper {
+  public static native int initialize(int module);
+
+  public static native void free(int handle);
+
+  public static native boolean checkSolenoidChannel(int channel);
+
+  public static native boolean getCompressor(int handle);
+
+  public static native void setClosedLoopControl(int handle, boolean enabled);
+
+  public static native boolean getClosedLoopControl(int handle);
+
+  public static native boolean getPressureSwitch(int handle);
+
+  public static native double getCompressorCurrent(int handle);
+
+  public static native boolean getCompressorCurrentTooHighFault(int handle);
+
+  public static native boolean getCompressorCurrentTooHighStickyFault(int handle);
+
+  public static native boolean getCompressorShortedFault(int handle);
+
+  public static native boolean getCompressorShortedStickyFault(int handle);
+
+  public static native boolean getCompressorNotConnectedFault(int handle);
+
+  public static native boolean getCompressorNotConnectedStickyFault(int handle);
+
+  public static native int getSolenoids(int handle);
+
+  public static native void setSolenoids(int handle, int mask, int values);
+
+  public static native int getSolenoidDisabledList(int handle);
+
+  public static native boolean getSolenoidVoltageFault(int handle);
+
+  public static native boolean getSolenoidVoltageStickyFault(int handle);
+
+  public static native void clearAllStickyFaults(int handle);
+
+  public static native void fireOneShot(int handle, int index);
+
+  public static native void setOneShotDuration(int handle, int index, int durMs);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/CompressorJNI.java b/hal/src/main/java/edu/wpi/first/hal/CompressorJNI.java
deleted file mode 100644
index 64e9e1d..0000000
--- a/hal/src/main/java/edu/wpi/first/hal/CompressorJNI.java
+++ /dev/null
@@ -1,38 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.hal;
-
-public class CompressorJNI extends JNIWrapper {
-  public static native int initializeCompressor(byte module);
-
-  public static native boolean checkCompressorModule(byte module);
-
-  public static native boolean getCompressor(int compressorHandle);
-
-  public static native void setCompressorClosedLoopControl(int compressorHandle, boolean value);
-
-  public static native boolean getCompressorClosedLoopControl(int compressorHandle);
-
-  public static native boolean getCompressorPressureSwitch(int compressorHandle);
-
-  public static native double getCompressorCurrent(int compressorHandle);
-
-  public static native boolean getCompressorCurrentTooHighFault(int compressorHandle);
-
-  public static native boolean getCompressorCurrentTooHighStickyFault(int compressorHandle);
-
-  public static native boolean getCompressorShortedStickyFault(int compressorHandle);
-
-  public static native boolean getCompressorShortedFault(int compressorHandle);
-
-  public static native boolean getCompressorNotConnectedStickyFault(int compressorHandle);
-
-  public static native boolean getCompressorNotConnectedFault(int compressorHandle);
-
-  public static native void clearAllPCMStickyFaults(byte compressorModule);
-}
diff --git a/hal/src/main/java/edu/wpi/first/hal/ConstantsJNI.java b/hal/src/main/java/edu/wpi/first/hal/ConstantsJNI.java
index 3db75f5..aba5b33 100644
--- a/hal/src/main/java/edu/wpi/first/hal/ConstantsJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/ConstantsJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/ControlWord.java b/hal/src/main/java/edu/wpi/first/hal/ControlWord.java
index 8353606..a568343 100644
--- a/hal/src/main/java/edu/wpi/first/hal/ControlWord.java
+++ b/hal/src/main/java/edu/wpi/first/hal/ControlWord.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
-/**
- * A wrapper for the HALControlWord bitfield.
- */
+/** A wrapper for the HALControlWord bitfield. */
 public class ControlWord {
   private boolean m_enabled;
   private boolean m_autonomous;
@@ -18,8 +13,13 @@
   private boolean m_fmsAttached;
   private boolean m_dsAttached;
 
-  void update(boolean enabled, boolean autonomous, boolean test, boolean emergencyStop,
-              boolean fmsAttached, boolean dsAttached) {
+  void update(
+      boolean enabled,
+      boolean autonomous,
+      boolean test,
+      boolean emergencyStop,
+      boolean fmsAttached,
+      boolean dsAttached) {
     m_enabled = enabled;
     m_autonomous = autonomous;
     m_test = test;
diff --git a/hal/src/main/java/edu/wpi/first/hal/CounterJNI.java b/hal/src/main/java/edu/wpi/first/hal/CounterJNI.java
index b7935d6..f164dbd 100644
--- a/hal/src/main/java/edu/wpi/first/hal/CounterJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/CounterJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -16,19 +13,19 @@
 
   public static native void setCounterAverageSize(int counterHandle, int size);
 
-  public static native void setCounterUpSource(int counterHandle, int digitalSourceHandle,
-                                               int analogTriggerType);
+  public static native void setCounterUpSource(
+      int counterHandle, int digitalSourceHandle, int analogTriggerType);
 
-  public static native void setCounterUpSourceEdge(int counterHandle, boolean risingEdge,
-                                                   boolean fallingEdge);
+  public static native void setCounterUpSourceEdge(
+      int counterHandle, boolean risingEdge, boolean fallingEdge);
 
   public static native void clearCounterUpSource(int counterHandle);
 
-  public static native void setCounterDownSource(int counterHandle, int digitalSourceHandle,
-                                                 int analogTriggerType);
+  public static native void setCounterDownSource(
+      int counterHandle, int digitalSourceHandle, int analogTriggerType);
 
-  public static native void setCounterDownSourceEdge(int counterHandle, boolean risingEdge,
-                                                     boolean fallingEdge);
+  public static native void setCounterDownSourceEdge(
+      int counterHandle, boolean risingEdge, boolean fallingEdge);
 
   public static native void clearCounterDownSource(int counterHandle);
 
@@ -36,15 +33,13 @@
 
   public static native void setCounterExternalDirectionMode(int counterHandle);
 
-  public static native void setCounterSemiPeriodMode(int counterHandle,
-                                                     boolean highSemiPeriod);
+  public static native void setCounterSemiPeriodMode(int counterHandle, boolean highSemiPeriod);
 
   public static native void setCounterPulseLengthMode(int counterHandle, double threshold);
 
   public static native int getCounterSamplesToAverage(int counterHandle);
 
-  public static native void setCounterSamplesToAverage(int counterHandle,
-                                                       int samplesToAverage);
+  public static native void setCounterSamplesToAverage(int counterHandle, int samplesToAverage);
 
   public static native void resetCounter(int counterHandle);
 
@@ -60,6 +55,5 @@
 
   public static native boolean getCounterDirection(int counterHandle);
 
-  public static native void setCounterReverseDirection(int counterHandle,
-                                                       boolean reverseDirection);
+  public static native void setCounterReverseDirection(int counterHandle, boolean reverseDirection);
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java b/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java
index ad83c3c..dab1aaf 100644
--- a/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/DIOJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -17,8 +14,7 @@
 
   public static native void setDIOSimDevice(int handle, int device);
 
-  // TODO(Thad): Switch this to use boolean
-  public static native void setDIO(int dioPortHandle, short value);
+  public static native void setDIO(int dioPortHandle, boolean value);
 
   public static native void setDIODirection(int dioPortHandle, boolean input);
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/DMAJNI.java b/hal/src/main/java/edu/wpi/first/hal/DMAJNI.java
new file mode 100644
index 0000000..21c06f1
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/DMAJNI.java
@@ -0,0 +1,57 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class DMAJNI extends JNIWrapper {
+  public static native int initialize();
+
+  public static native void free(int handle);
+
+  public static native void setPause(int handle, boolean pause);
+
+  public static native void setTimedTrigger(int handle, double periodSeconds);
+
+  public static native void setTimedTriggerCycles(int handle, int cycles);
+
+  public static native void addEncoder(int handle, int encoderHandle);
+
+  public static native void addEncoderPeriod(int handle, int encoderHandle);
+
+  public static native void addCounter(int handle, int counterHandle);
+
+  public static native void addCounterPeriod(int handle, int counterHandle);
+
+  public static native void addDigitalSource(int handle, int digitalSourceHandle);
+
+  public static native void addDutyCycle(int handle, int dutyCycleHandle);
+
+  public static native void addAnalogInput(int handle, int analogInputHandle);
+
+  public static native void addAveragedAnalogInput(int handle, int analogInputHandle);
+
+  public static native void addAnalogAccumulator(int handle, int analogInputHandle);
+
+  public static native int setExternalTrigger(
+      int handle, int digitalSourceHandle, int analogTriggerType, boolean rising, boolean falling);
+
+  public static native void clearSensors(int handle);
+
+  public static native void clearExternalTriggers(int handle);
+
+  public static native void startDMA(int handle, int queueDepth);
+
+  public static native void stopDMA(int handle);
+
+  // 0-21 channelOffsets
+  // 22: capture size
+  // 23: triggerChannels (bitflags)
+  // 24: remaining
+  // 25: read status
+  public static native long readDMA(
+      int handle, double timeoutSeconds, int[] buffer, int[] sampleStore);
+
+  public static native DMAJNISample.BaseStore getSensorReadData(int handle);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/DMAJNISample.java b/hal/src/main/java/edu/wpi/first/hal/DMAJNISample.java
new file mode 100644
index 0000000..78a0e99
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/DMAJNISample.java
@@ -0,0 +1,169 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.hal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class DMAJNISample {
+  private static final int kEnable_Accumulator0 = 8;
+  private static final int kEnable_Accumulator1 = 9;
+
+  static class BaseStore {
+    public final int m_valueType;
+    public final int m_index;
+
+    BaseStore(int valueType, int index) {
+      this.m_valueType = valueType;
+      this.m_index = index;
+    }
+  }
+
+  private final int[] m_dataBuffer = new int[100];
+  private final int[] m_storage = new int[100];
+  private long m_timeStamp;
+  private Map<Integer, BaseStore> m_propertyMap = new HashMap<>();
+
+  public int update(int dmaHandle, double timeoutSeconds) {
+    m_timeStamp = DMAJNI.readDMA(dmaHandle, timeoutSeconds, m_dataBuffer, m_storage);
+    return m_storage[25];
+  }
+
+  public int getCaptureSize() {
+    return m_storage[22];
+  }
+
+  public int getTriggerChannels() {
+    return m_storage[23];
+  }
+
+  public int getRemaining() {
+    return m_storage[24];
+  }
+
+  public long getTime() {
+    return m_timeStamp;
+  }
+
+  private BaseStore addSensorInternal(int handle) {
+    BaseStore sensorData = DMAJNI.getSensorReadData(handle);
+    m_propertyMap.put(handle, sensorData);
+    return sensorData;
+  }
+
+  public void addSensor(int handle) {
+    addSensorInternal(handle);
+  }
+
+  private int readValue(int valueType, int index) {
+    int offset = m_storage[valueType];
+    if (offset == -1) {
+      throw new RuntimeException("Resource not found in DMA capture");
+    }
+    return m_dataBuffer[offset + index];
+  }
+
+  public int getEncoder(int encoderHandle) {
+    BaseStore data = m_propertyMap.get(encoderHandle);
+    if (data == null) {
+      data = addSensorInternal(encoderHandle);
+    }
+    return readValue(data.m_valueType, data.m_index);
+  }
+
+  public int getEncoderPeriod(int encoderHandle) {
+    BaseStore data = m_propertyMap.get(encoderHandle);
+    if (data == null) {
+      data = addSensorInternal(encoderHandle);
+    }
+    // + 2 Hack, but needed to not have to call into JNI
+    return readValue(data.m_valueType + 2, data.m_index);
+  }
+
+  public int getCounter(int counterHandle) {
+    BaseStore data = m_propertyMap.get(counterHandle);
+    if (data == null) {
+      data = addSensorInternal(counterHandle);
+    }
+    return readValue(data.m_valueType, data.m_index);
+  }
+
+  public int getCounterPeriod(int counterHandle) {
+    BaseStore data = m_propertyMap.get(counterHandle);
+    if (data == null) {
+      data = addSensorInternal(counterHandle);
+    }
+    // Hack, but needed to not have to call into JNI
+    return readValue(data.m_valueType + 2, data.m_index);
+  }
+
+  public boolean getDigitalSource(int digitalSourceHandle) {
+    BaseStore data = m_propertyMap.get(digitalSourceHandle);
+    if (data == null) {
+      data = addSensorInternal(digitalSourceHandle);
+    }
+
+    int value = readValue(data.m_valueType, 0);
+
+    return ((value >> data.m_index) & 0x1) != 0;
+  }
+
+  public int getAnalogInput(int analogInputHandle) {
+    BaseStore data = m_propertyMap.get(analogInputHandle);
+    if (data == null) {
+      data = addSensorInternal(analogInputHandle);
+    }
+
+    int value = readValue(data.m_valueType, data.m_index / 2);
+    if ((data.m_index % 2) != 0) {
+      return (value >>> 16) & 0xFFFF;
+    } else {
+      return value & 0xFFFF;
+    }
+  }
+
+  public int getAnalogInputAveraged(int analogInputHandle) {
+    BaseStore data = m_propertyMap.get(analogInputHandle);
+    if (data == null) {
+      data = addSensorInternal(analogInputHandle);
+    }
+
+    // + 2 Hack, but needed to not have to call into JNI
+    int value = readValue(data.m_valueType + 2, data.m_index);
+    return value;
+  }
+
+  public void getAnalogAccumulator(int analogInputHandle, AccumulatorResult result) {
+    BaseStore data = m_propertyMap.get(analogInputHandle);
+    if (data == null) {
+      data = addSensorInternal(analogInputHandle);
+    }
+
+    if (data.m_index == 0) {
+      int val0 = readValue(kEnable_Accumulator0, 0);
+      int val1 = readValue(kEnable_Accumulator0, 1);
+      int val2 = readValue(kEnable_Accumulator0, 2);
+      result.count = val2;
+      result.value = ((long) val1 << 32) | val0;
+    } else if (data.m_index == 1) {
+      int val0 = readValue(kEnable_Accumulator1, 0);
+      int val1 = readValue(kEnable_Accumulator1, 1);
+      int val2 = readValue(kEnable_Accumulator1, 2);
+      result.count = val2;
+      result.value = ((long) val1 << 32) | val0;
+    } else {
+      throw new RuntimeException("Resource not found in DMA capture");
+    }
+  }
+
+  public int getDutyCycleOutput(int dutyCycleHandle) {
+    BaseStore data = m_propertyMap.get(dutyCycleHandle);
+    if (data == null) {
+      data = addSensorInternal(dutyCycleHandle);
+    }
+    return readValue(data.m_valueType, data.m_index);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/DigitalGlitchFilterJNI.java b/hal/src/main/java/edu/wpi/first/hal/DigitalGlitchFilterJNI.java
index aa818cf..cf0a781 100644
--- a/hal/src/main/java/edu/wpi/first/hal/DigitalGlitchFilterJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/DigitalGlitchFilterJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/DutyCycleJNI.java b/hal/src/main/java/edu/wpi/first/hal/DutyCycleJNI.java
index f0f93e1..a1bba6f 100644
--- a/hal/src/main/java/edu/wpi/first/hal/DutyCycleJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/DutyCycleJNI.java
@@ -1,19 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 public class DutyCycleJNI extends JNIWrapper {
   public static native int initialize(int digitalSourceHandle, int analogTriggerType);
+
   public static native void free(int handle);
 
   public static native int getFrequency(int handle);
+
   public static native double getOutput(int handle);
+
   public static native int getOutputRaw(int handle);
+
   public static native int getOutputScaleFactor(int handle);
 
   @SuppressWarnings("AbbreviationAsWordInName")
diff --git a/hal/src/main/java/edu/wpi/first/hal/EncoderJNI.java b/hal/src/main/java/edu/wpi/first/hal/EncoderJNI.java
index 40fa1c1..f67e3a5 100644
--- a/hal/src/main/java/edu/wpi/first/hal/EncoderJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/EncoderJNI.java
@@ -1,16 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 public class EncoderJNI extends JNIWrapper {
-  public static native int initializeEncoder(int digitalSourceHandleA, int analogTriggerTypeA,
-                                             int digitalSourceHandleB, int analogTriggerTypeB,
-                                             boolean reverseDirection, int encodingType);
+  public static native int initializeEncoder(
+      int digitalSourceHandleA,
+      int analogTriggerTypeA,
+      int digitalSourceHandleB,
+      int analogTriggerTypeB,
+      boolean reverseDirection,
+      int encodingType);
 
   public static native void freeEncoder(int encoderHandle);
 
@@ -40,16 +41,14 @@
 
   public static native void setEncoderDistancePerPulse(int encoderHandle, double distancePerPulse);
 
-  public static native void setEncoderReverseDirection(int encoderHandle,
-                                                       boolean reverseDirection);
+  public static native void setEncoderReverseDirection(int encoderHandle, boolean reverseDirection);
 
-  public static native void setEncoderSamplesToAverage(int encoderHandle,
-                                                       int samplesToAverage);
+  public static native void setEncoderSamplesToAverage(int encoderHandle, int samplesToAverage);
 
   public static native int getEncoderSamplesToAverage(int encoderHandle);
 
-  public static native void setEncoderIndexSource(int encoderHandle, int digitalSourceHandle,
-                                                  int analogTriggerType, int indexingType);
+  public static native void setEncoderIndexSource(
+      int encoderHandle, int digitalSourceHandle, int analogTriggerType, int indexingType);
 
   @SuppressWarnings("AbbreviationAsWordInName")
   public static native int getEncoderFPGAIndex(int encoderHandle);
diff --git a/hal/src/main/java/edu/wpi/first/hal/HAL.java b/hal/src/main/java/edu/wpi/first/hal/HAL.java
index 5e07488..af97450 100644
--- a/hal/src/main/java/edu/wpi/first/hal/HAL.java
+++ b/hal/src/main/java/edu/wpi/first/hal/HAL.java
@@ -1,16 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
- * JNI Wrapper for HAL<br>.
+ * JNI Wrapper for HAL<br>
+ * .
  */
 @SuppressWarnings({"AbbreviationAsWordInName", "MethodName"})
 public final class HAL extends JNIWrapper {
@@ -26,6 +26,97 @@
 
   public static native void exitMain();
 
+  private static native void simPeriodicBeforeNative();
+
+  private static final List<Runnable> s_simPeriodicBefore = new ArrayList<>();
+
+  public static class SimPeriodicBeforeCallback implements AutoCloseable {
+    private SimPeriodicBeforeCallback(Runnable r) {
+      m_run = r;
+    }
+
+    @Override
+    public void close() {
+      synchronized (s_simPeriodicBefore) {
+        s_simPeriodicBefore.remove(m_run);
+      }
+    }
+
+    private final Runnable m_run;
+  }
+
+  /**
+   * Registers a callback to be run by IterativeRobotBase prior to the user's simulationPeriodic
+   * code.
+   *
+   * @param r runnable
+   * @return Callback object (must be retained for callback to stay active).
+   */
+  public static SimPeriodicBeforeCallback registerSimPeriodicBeforeCallback(Runnable r) {
+    synchronized (s_simPeriodicBefore) {
+      s_simPeriodicBefore.add(r);
+    }
+    return new SimPeriodicBeforeCallback(r);
+  }
+
+  /**
+   * Runs SimPeriodicBefore callbacks. IterativeRobotBase calls this prior to the user's
+   * simulationPeriodic code.
+   */
+  public static void simPeriodicBefore() {
+    simPeriodicBeforeNative();
+    synchronized (s_simPeriodicBefore) {
+      for (Runnable r : s_simPeriodicBefore) {
+        r.run();
+      }
+    }
+  }
+
+  private static native void simPeriodicAfterNative();
+
+  private static final List<Runnable> s_simPeriodicAfter = new ArrayList<>();
+
+  public static class SimPeriodicAfterCallback implements AutoCloseable {
+    private SimPeriodicAfterCallback(Runnable r) {
+      m_run = r;
+    }
+
+    @Override
+    public void close() {
+      synchronized (s_simPeriodicAfter) {
+        s_simPeriodicAfter.remove(m_run);
+      }
+    }
+
+    private final Runnable m_run;
+  }
+
+  /**
+   * Registers a callback to be run by IterativeRobotBase after the user's simulationPeriodic code.
+   *
+   * @param r runnable
+   * @return Callback object (must be retained for callback to stay active).
+   */
+  public static SimPeriodicAfterCallback registerSimPeriodicAfterCallback(Runnable r) {
+    synchronized (s_simPeriodicAfter) {
+      s_simPeriodicAfter.add(r);
+    }
+    return new SimPeriodicAfterCallback(r);
+  }
+
+  /**
+   * Runs SimPeriodicAfter callbacks. IterativeRobotBase calls this after the user's
+   * simulationPeriodic code.
+   */
+  public static void simPeriodicAfter() {
+    simPeriodicAfterNative();
+    synchronized (s_simPeriodicAfter) {
+      for (Runnable r : s_simPeriodicAfter) {
+        r.run();
+      }
+    }
+  }
+
   public static native void observeUserProgramStarting();
 
   public static native void observeUserProgramDisabled();
@@ -45,33 +136,38 @@
   }
 
   /**
-   * Report the usage of a resource of interest. <br>
+   * Report the usage of a resource of interest.
    *
    * <p>Original signature: <code>uint32_t report(tResourceType, uint8_t, uint8_t, const
    * char*)</code>
    *
-   * @param resource       one of the values in the tResourceType above (max value 51). <br>
-   * @param instanceNumber an index that identifies the resource instance. <br>
-   * @param context        an optional additional context number for some cases (such as module
-   *                       number). Set to 0 to omit. <br>
-   * @param feature        a string to be included describing features in use on a specific
-   *                       resource. Setting the same resource more than once allows you to change
-   *                       the feature string.
+   * @param resource one of the values in the tResourceType above (max value 51).
+   * @param instanceNumber an index that identifies the resource instance.
+   * @param context an optional additional context number for some cases (such as module number).
+   *     Set to 0 to omit.
+   * @param feature a string to be included describing features in use on a specific resource.
+   *     Setting the same resource more than once allows you to change the feature string.
+   * @return TODO
    */
   public static native int report(int resource, int instanceNumber, int context, String feature);
 
   public static native int nativeGetControlWord();
 
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   public static void getControlWord(ControlWord controlWord) {
     int word = nativeGetControlWord();
-    controlWord.update((word & 1) != 0, ((word >> 1) & 1) != 0, ((word >> 2) & 1) != 0,
-        ((word >> 3) & 1) != 0, ((word >> 4) & 1) != 0, ((word >> 5) & 1) != 0);
+    controlWord.update(
+        (word & 1) != 0,
+        ((word >> 1) & 1) != 0,
+        ((word >> 2) & 1) != 0,
+        ((word >> 3) & 1) != 0,
+        ((word >> 4) & 1) != 0,
+        ((word >> 5) & 1) != 0);
   }
 
   private static native int nativeGetAllianceStation();
 
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   public static AllianceStationID getAllianceStation() {
     switch (nativeGetAllianceStation()) {
       case 0:
@@ -91,13 +187,13 @@
     }
   }
 
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   public static native boolean isNewControlData();
 
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   public static native void releaseDSMutex();
 
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   public static native boolean waitForDSDataTimeout(double timeout);
 
   public static int kMaxJoystickAxes = 12;
@@ -109,8 +205,8 @@
 
   public static native int getJoystickButtons(byte joystickNum, ByteBuffer count);
 
-  public static native int setJoystickOutputs(byte joystickNum, int outputs, short leftRumble,
-                                              short rightRumble);
+  public static native int setJoystickOutputs(
+      byte joystickNum, int outputs, short leftRumble, short rightRumble);
 
   public static native int getJoystickIsXbox(byte joystickNum);
 
@@ -128,9 +224,14 @@
 
   public static native int getMatchInfo(MatchInfoData info);
 
-  public static native int sendError(boolean isError, int errorCode, boolean isLVCode,
-                                     String details, String location, String callStack,
-                                     boolean printMsg);
+  public static native int sendError(
+      boolean isError,
+      int errorCode,
+      boolean isLVCode,
+      String details,
+      String location,
+      String callStack,
+      boolean printMsg);
 
   public static native int sendConsoleLine(String line);
 
@@ -138,7 +239,5 @@
 
   public static native int getPort(byte channel);
 
-  private HAL() {
-
-  }
+  private HAL() {}
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/HALUtil.java b/hal/src/main/java/edu/wpi/first/hal/HALUtil.java
index 0e5fe21..4da20a2 100644
--- a/hal/src/main/java/edu/wpi/first/hal/HALUtil.java
+++ b/hal/src/main/java/edu/wpi/first/hal/HALUtil.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -18,6 +15,10 @@
   public static final int NO_AVAILABLE_RESOURCES = -104;
   public static final int PARAMETER_OUT_OF_RANGE = -1028;
 
+  public static final int RUNTIME_ROBORIO = 0;
+  public static final int RUNTIME_ROBORIO2 = 1;
+  public static final int RUNTIME_SIMULATION = 2;
+
   public static native short getFPGAVersion();
 
   public static native int getFPGARevision();
@@ -38,7 +39,5 @@
     return getHALstrerror(getHALErrno());
   }
 
-  private HALUtil() {
-
-  }
+  private HALUtil() {}
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/HALValue.java b/hal/src/main/java/edu/wpi/first/hal/HALValue.java
index 636af8f..ded57de 100644
--- a/hal/src/main/java/edu/wpi/first/hal/HALValue.java
+++ b/hal/src/main/java/edu/wpi/first/hal/HALValue.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
@@ -30,9 +27,7 @@
     m_long = value;
   }
 
-  private HALValue() {
-
-  }
+  private HALValue() {}
 
   /**
    * Get the type of the value.
@@ -44,7 +39,7 @@
   }
 
   /**
-   * Get the value as a boolean.  Does not perform type checking.
+   * Get the value as a boolean. Does not perform type checking.
    *
    * @return value contents
    */
@@ -53,7 +48,7 @@
   }
 
   /**
-   * Get the value as a long.  Does not perform type checking.
+   * Get the value as a long. Does not perform type checking.
    *
    * @return value contents
    */
@@ -62,7 +57,7 @@
   }
 
   /**
-   * Get the value as a double.  Does not perform type checking.
+   * Get the value as a double. Does not perform type checking.
    *
    * @return value contents
    */
@@ -71,7 +66,7 @@
   }
 
   /**
-   * Get the native long value.  Does not perform type checking.
+   * Get the native long value. Does not perform type checking.
    *
    * @return value contents
    */
@@ -80,7 +75,7 @@
   }
 
   /**
-   * Get the native double value.  Does not perform type checking.
+   * Get the native double value. Does not perform type checking.
    *
    * @return value contents
    */
@@ -152,15 +147,15 @@
    */
   public static HALValue fromNative(int type, long value1, double value2) {
     switch (type) {
-      case 0x01:
+      case kBoolean:
         return makeBoolean(value1 != 0);
-      case 0x02:
+      case kDouble:
         return makeDouble(value2);
-      case 0x16:
+      case kEnum:
         return makeEnum((int) value1);
-      case 0x32:
+      case kInt:
         return makeInt((int) value1);
-      case 0x64:
+      case kLong:
         return makeLong(value1);
       default:
         return makeUnassigned();
diff --git a/hal/src/main/java/edu/wpi/first/hal/I2CJNI.java b/hal/src/main/java/edu/wpi/first/hal/I2CJNI.java
index 12a9af0..821c89b 100644
--- a/hal/src/main/java/edu/wpi/first/hal/I2CJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/I2CJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -13,21 +10,30 @@
 public class I2CJNI extends JNIWrapper {
   public static native void i2CInitialize(int port);
 
-  public static native int i2CTransaction(int port, byte address, ByteBuffer dataToSend,
-                                          byte sendSize, ByteBuffer dataReceived, byte receiveSize);
+  public static native int i2CTransaction(
+      int port,
+      byte address,
+      ByteBuffer dataToSend,
+      byte sendSize,
+      ByteBuffer dataReceived,
+      byte receiveSize);
 
-  public static native int i2CTransactionB(int port, byte address, byte[] dataToSend,
-                                           byte sendSize, byte[] dataReceived, byte receiveSize);
+  public static native int i2CTransactionB(
+      int port,
+      byte address,
+      byte[] dataToSend,
+      byte sendSize,
+      byte[] dataReceived,
+      byte receiveSize);
 
   public static native int i2CWrite(int port, byte address, ByteBuffer dataToSend, byte sendSize);
 
   public static native int i2CWriteB(int port, byte address, byte[] dataToSend, byte sendSize);
 
-  public static native int i2CRead(int port, byte address, ByteBuffer dataReceived,
-                                   byte receiveSize);
+  public static native int i2CRead(
+      int port, byte address, ByteBuffer dataReceived, byte receiveSize);
 
-  public static native int i2CReadB(int port, byte address, byte[] dataReceived,
-                                    byte receiveSize);
+  public static native int i2CReadB(int port, byte address, byte[] dataReceived, byte receiveSize);
 
   public static native void i2CClose(int port);
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java b/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java
index e370d5b..a47a364 100644
--- a/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java
@@ -1,43 +1,28 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 public class InterruptJNI extends JNIWrapper {
   public static final int HalInvalidHandle = 0;
 
-  public interface InterruptJNIHandlerFunction {
-    void apply(int interruptAssertedMask, Object param);
-  }
-
-  public static native int initializeInterrupts(boolean watcher);
+  public static native int initializeInterrupts();
 
   public static native void cleanInterrupts(int interruptHandle);
 
-  public static native int waitForInterrupt(int interruptHandle, double timeout,
-                                            boolean ignorePrevious);
-
-  public static native void enableInterrupts(int interruptHandle);
-
-  public static native void disableInterrupts(int interruptHandle);
+  public static native int waitForInterrupt(
+      int interruptHandle, double timeout, boolean ignorePrevious);
 
   public static native long readInterruptRisingTimestamp(int interruptHandle);
 
   public static native long readInterruptFallingTimestamp(int interruptHandle);
 
-  public static native void requestInterrupts(int interruptHandle, int digitalSourceHandle,
-                                              int analogTriggerType);
+  public static native void requestInterrupts(
+      int interruptHandle, int digitalSourceHandle, int analogTriggerType);
 
-  public static native void attachInterruptHandler(int interruptHandle,
-                                                   InterruptJNIHandlerFunction handler,
-                                                   Object param);
-
-  public static native void setInterruptUpSourceEdge(int interruptHandle, boolean risingEdge,
-                                                     boolean fallingEdge);
+  public static native void setInterruptUpSourceEdge(
+      int interruptHandle, boolean risingEdge, boolean fallingEdge);
 
   public static native void releaseWaitingInterrupt(int interruptHandle);
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java b/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java
index 63ad39f..b2b54da 100644
--- a/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java
+++ b/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java
@@ -1,20 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
+import edu.wpi.first.util.RuntimeLoader;
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import edu.wpi.first.wpiutil.RuntimeLoader;
-
-/**
- * Base class for all JNI wrappers.
- */
+/** Base class for all JNI wrappers. */
 public class JNIWrapper {
   static boolean libraryLoaded = false;
   static RuntimeLoader<JNIWrapper> loader = null;
@@ -34,7 +28,9 @@
   static {
     if (Helper.getExtractOnStaticLoad()) {
       try {
-        loader = new RuntimeLoader<>("wpiHaljni", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class);
+        loader =
+            new RuntimeLoader<>(
+                "wpiHaljni", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class);
         loader.loadLibrary();
       } catch (IOException ex) {
         ex.printStackTrace();
@@ -46,12 +42,16 @@
 
   /**
    * Force load the library.
+   *
+   * @throws IOException if the library load failed
    */
   public static synchronized void forceLoad() throws IOException {
     if (libraryLoaded) {
       return;
     }
-    loader = new RuntimeLoader<>("wpiHaljni", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class);
+    loader =
+        new RuntimeLoader<>(
+            "wpiHaljni", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class);
     loader.loadLibrary();
     libraryLoaded = true;
   }
diff --git a/hal/src/main/java/edu/wpi/first/hal/MatchInfoData.java b/hal/src/main/java/edu/wpi/first/hal/MatchInfoData.java
index 2f11515..6737c58 100644
--- a/hal/src/main/java/edu/wpi/first/hal/MatchInfoData.java
+++ b/hal/src/main/java/edu/wpi/first/hal/MatchInfoData.java
@@ -1,52 +1,47 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
-/**
- * Structure for holding the match info data request.
- */
+/** Structure for holding the match info data request. */
 public class MatchInfoData {
-  /**
-   * Stores the event name.
-   */
+  /** Stores the event name. */
   @SuppressWarnings("MemberName")
   public String eventName = "";
 
-  /**
-   * Stores the game specific message.
-   */
+  /** Stores the game specific message. */
   @SuppressWarnings("MemberName")
   public String gameSpecificMessage = "";
 
-  /**
-   * Stores the match number.
-   */
+  /** Stores the match number. */
   @SuppressWarnings("MemberName")
   public int matchNumber;
 
-  /**
-   * Stores the replay number.
-   */
+  /** Stores the replay number. */
   @SuppressWarnings("MemberName")
   public int replayNumber;
 
-  /**
-   * Stores the match type.
-   */
+  /** Stores the match type. */
   @SuppressWarnings("MemberName")
   public int matchType;
 
   /**
    * Called from JNI to set the structure data.
+   *
+   * @param eventName Event name.
+   * @param gameSpecificMessage Game-specific message.
+   * @param matchNumber Match number.
+   * @param replayNumber Replay number.
+   * @param matchType Match type.
    */
-  @SuppressWarnings("JavadocMethod")
-  public void setData(String eventName, String gameSpecificMessage,
-                      int matchNumber, int replayNumber, int matchType) {
+  @SuppressWarnings("MissingJavadocMethod")
+  public void setData(
+      String eventName,
+      String gameSpecificMessage,
+      int matchNumber,
+      int replayNumber,
+      int matchType) {
     this.eventName = eventName;
     this.gameSpecificMessage = gameSpecificMessage;
     this.matchNumber = matchNumber;
diff --git a/hal/src/main/java/edu/wpi/first/hal/NotifierJNI.java b/hal/src/main/java/edu/wpi/first/hal/NotifierJNI.java
index 000c7d6..c8f4eef 100644
--- a/hal/src/main/java/edu/wpi/first/hal/NotifierJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/NotifierJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -16,38 +13,63 @@
 public class NotifierJNI extends JNIWrapper {
   /**
    * Initializes the notifier.
+   *
+   * @return True on success.
    */
   public static native int initializeNotifier();
 
   /**
+   * Sets the HAL notifier thread priority.
+   *
+   * @param realTime Set to true to set a real-time priority, false for standard priority.
+   * @param priority Priority to set the thread to. For real-time, this is 1-99 with 99 being
+   *     highest. For non-real-time, this is forced to 0. See "man 7 sched" for more details.
+   * @return True on success.
+   */
+  public static native boolean setHALThreadPriority(boolean realTime, int priority);
+
+  /**
    * Sets the name of the notifier.
+   *
+   * @param notifierHandle Notifier handle.
+   * @param name Notifier name.
    */
   public static native void setNotifierName(int notifierHandle, String name);
 
   /**
-   * Wakes up the waiter with time=0.  Note: after this function is called, all
-   * calls to waitForNotifierAlarm() will immediately start returning 0.
+   * Wakes up the waiter with time=0. Note: after this function is called, all calls to
+   * waitForNotifierAlarm() will immediately start returning 0.
+   *
+   * @param notifierHandle Notifier handle.
    */
   public static native void stopNotifier(int notifierHandle);
 
   /**
    * Deletes the notifier object when we are done with it.
+   *
+   * @param notifierHandle Notifier handle.
    */
   public static native void cleanNotifier(int notifierHandle);
 
   /**
    * Sets the notifier to wakeup the waiter in another triggerTime microseconds.
+   *
+   * @param notifierHandle Notifier handle.
+   * @param triggerTime Trigger time in microseconds.
    */
   public static native void updateNotifierAlarm(int notifierHandle, long triggerTime);
 
   /**
-   * Cancels any pending wakeups set by updateNotifierAlarm().  Does NOT wake
-   * up any waiters.
+   * Cancels any pending wakeups set by updateNotifierAlarm(). Does NOT wake up any waiters.
+   *
+   * @param notifierHandle Notifier handle.
    */
   public static native void cancelNotifierAlarm(int notifierHandle);
 
   /**
    * Block until woken up by an alarm (or stop).
+   *
+   * @param notifierHandle Notifier handle.
    * @return Time when woken up.
    */
   public static native long waitForNotifierAlarm(int notifierHandle);
diff --git a/hal/src/main/java/edu/wpi/first/hal/PDPJNI.java b/hal/src/main/java/edu/wpi/first/hal/PDPJNI.java
deleted file mode 100644
index e2d7fcc..0000000
--- a/hal/src/main/java/edu/wpi/first/hal/PDPJNI.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.hal;
-
-@SuppressWarnings("AbbreviationAsWordInName")
-public class PDPJNI extends JNIWrapper {
-  public static native int initializePDP(int module);
-
-  public static native boolean checkPDPModule(int module);
-
-  public static native boolean checkPDPChannel(int channel);
-
-  public static native double getPDPTemperature(int handle);
-
-  public static native double getPDPVoltage(int handle);
-
-  public static native double getPDPChannelCurrent(byte channel, int handle);
-
-  public static native void getPDPAllCurrents(int handle, double[] currents);
-
-  public static native double getPDPTotalCurrent(int handle);
-
-  public static native double getPDPTotalPower(int handle);
-
-  public static native double getPDPTotalEnergy(int handle);
-
-  public static native void resetPDPTotalEnergy(int handle);
-
-  public static native void clearPDPStickyFaults(int handle);
-}
diff --git a/hal/src/main/java/edu/wpi/first/hal/PWMConfigDataResult.java b/hal/src/main/java/edu/wpi/first/hal/PWMConfigDataResult.java
index d29b0df..e64d6da 100644
--- a/hal/src/main/java/edu/wpi/first/hal/PWMConfigDataResult.java
+++ b/hal/src/main/java/edu/wpi/first/hal/PWMConfigDataResult.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
-/**
- * Structure for holding the config data result for PWM.
- */
+/** Structure for holding the config data result for PWM. */
 public class PWMConfigDataResult {
   PWMConfigDataResult(int max, int deadbandMax, int center, int deadbandMin, int min) {
     this.max = max;
@@ -19,33 +14,23 @@
     this.min = min;
   }
 
-  /**
-   * The maximum PWM value.
-   */
+  /** The maximum PWM value. */
   @SuppressWarnings("MemberName")
   public int max;
 
-  /**
-   * The deadband maximum PWM value.
-   */
+  /** The deadband maximum PWM value. */
   @SuppressWarnings("MemberName")
   public int deadbandMax;
 
-  /**
-   * The center PWM value.
-   */
+  /** The center PWM value. */
   @SuppressWarnings("MemberName")
   public int center;
 
-  /**
-   * The deadband minimum PWM value.
-   */
+  /** The deadband minimum PWM value. */
   @SuppressWarnings("MemberName")
   public int deadbandMin;
 
-  /**
-   * The minimum PWM value.
-   */
+  /** The minimum PWM value. */
   @SuppressWarnings("MemberName")
   public int min;
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/PWMJNI.java b/hal/src/main/java/edu/wpi/first/hal/PWMJNI.java
index 3af6f96..946ad07 100644
--- a/hal/src/main/java/edu/wpi/first/hal/PWMJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/PWMJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -15,13 +12,21 @@
 
   public static native void freePWMPort(int pwmPortHandle);
 
-  public static native void setPWMConfigRaw(int pwmPortHandle, int maxPwm,
-                                            int deadbandMaxPwm, int centerPwm,
-                                            int deadbandMinPwm, int minPwm);
+  public static native void setPWMConfigRaw(
+      int pwmPortHandle,
+      int maxPwm,
+      int deadbandMaxPwm,
+      int centerPwm,
+      int deadbandMinPwm,
+      int minPwm);
 
-  public static native void setPWMConfig(int pwmPortHandle, double maxPwm,
-                                         double deadbandMaxPwm, double centerPwm,
-                                         double deadbandMinPwm, double minPwm);
+  public static native void setPWMConfig(
+      int pwmPortHandle,
+      double maxPwm,
+      double deadbandMaxPwm,
+      double centerPwm,
+      double deadbandMinPwm,
+      double minPwm);
 
   public static native PWMConfigDataResult getPWMConfigRaw(int pwmPortHandle);
 
@@ -41,7 +46,7 @@
 
   public static native double getPWMPosition(int pwmPortHandle);
 
-  public static native  void setPWMDisabled(int pwmPortHandle);
+  public static native void setPWMDisabled(int pwmPortHandle);
 
   public static native void latchPWMZero(int pwmPortHandle);
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/PortsJNI.java b/hal/src/main/java/edu/wpi/first/hal/PortsJNI.java
index a2ac60b..6a06ff9 100644
--- a/hal/src/main/java/edu/wpi/first/hal/PortsJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/PortsJNI.java
@@ -1,12 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
+@SuppressWarnings("AbbreviationAsWordInName")
 public class PortsJNI extends JNIWrapper {
   public static native int getNumAccumulators();
 
@@ -36,11 +34,19 @@
 
   public static native int getNumRelayHeaders();
 
-  public static native int getNumPCMModules();
+  public static native int getNumCTREPCMModules();
 
-  public static native int getNumSolenoidChannels();
+  public static native int getNumCTRESolenoidChannels();
 
-  public static native int getNumPDPModules();
+  public static native int getNumCTREPDPModules();
 
-  public static native int getNumPDPChannels();
+  public static native int getNumCTREPDPChannels();
+
+  public static native int getNumREVPDHModules();
+
+  public static native int getNumREVPDHChannels();
+
+  public static native int getNumREVPHModules();
+
+  public static native int getNumREVPHChannels();
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/PowerDistributionJNI.java b/hal/src/main/java/edu/wpi/first/hal/PowerDistributionJNI.java
new file mode 100644
index 0000000..b2ac61a
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/PowerDistributionJNI.java
@@ -0,0 +1,49 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class PowerDistributionJNI extends JNIWrapper {
+  public static final int AUTOMATIC_TYPE = 0;
+  public static final int CTRE_TYPE = 1;
+  public static final int REV_TYPE = 2;
+  public static final int DEFAULT_MODULE = -1;
+
+  public static native int initialize(int module, int type);
+
+  public static native void free(int handle);
+
+  public static native int getModuleNumber(int handle);
+
+  public static native boolean checkModule(int module, int type);
+
+  public static native boolean checkChannel(int handle, int channel);
+
+  public static native int getType(int handle);
+
+  public static native int getNumChannels(int handle);
+
+  public static native double getTemperature(int handle);
+
+  public static native double getVoltage(int handle);
+
+  public static native double getChannelCurrent(int handle, int channel);
+
+  public static native void getAllCurrents(int handle, double[] currents);
+
+  public static native double getTotalCurrent(int handle);
+
+  public static native double getTotalPower(int handle);
+
+  public static native double getTotalEnergy(int handle);
+
+  public static native void resetTotalEnergy(int handle);
+
+  public static native void clearStickyFaults(int handle);
+
+  public static native boolean getSwitchableChannel(int handle);
+
+  public static native void setSwitchableChannel(int handle, boolean enabled);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/PowerJNI.java b/hal/src/main/java/edu/wpi/first/hal/PowerJNI.java
index 7a0a376..0bea6ed 100644
--- a/hal/src/main/java/edu/wpi/first/hal/PowerJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/PowerJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -35,4 +32,8 @@
   public static native boolean getUserActive3V3();
 
   public static native int getUserCurrentFaults3V3();
+
+  public static native void setBrownoutVoltage(double voltage);
+
+  public static native double getBrownoutVoltage();
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/REVPHJNI.java b/hal/src/main/java/edu/wpi/first/hal/REVPHJNI.java
new file mode 100644
index 0000000..a164106
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/REVPHJNI.java
@@ -0,0 +1,32 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.hal;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class REVPHJNI extends JNIWrapper {
+  public static native int initialize(int module);
+
+  public static native void free(int handle);
+
+  public static native boolean checkSolenoidChannel(int channel);
+
+  public static native boolean getCompressor(int handle);
+
+  public static native void setClosedLoopControl(int handle, boolean enabled);
+
+  public static native boolean getClosedLoopControl(int handle);
+
+  public static native boolean getPressureSwitch(int handle);
+
+  public static native double getAnalogPressure(int handle, int channel);
+
+  public static native double getCompressorCurrent(int handle);
+
+  public static native int getSolenoids(int handle);
+
+  public static native void setSolenoids(int handle, int mask, int values);
+
+  public static native void fireOneShot(int handle, int index, int durMs);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/RelayJNI.java b/hal/src/main/java/edu/wpi/first/hal/RelayJNI.java
index 1b507dc..eee2854 100644
--- a/hal/src/main/java/edu/wpi/first/hal/RelayJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/RelayJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java b/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java
index c203213..05ac08a 100644
--- a/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/SPIJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
@@ -13,11 +10,11 @@
 public class SPIJNI extends JNIWrapper {
   public static native void spiInitialize(int port);
 
-  public static native int spiTransaction(int port, ByteBuffer dataToSend,
-                                          ByteBuffer dataReceived, byte size);
+  public static native int spiTransaction(
+      int port, ByteBuffer dataToSend, ByteBuffer dataReceived, byte size);
 
-  public static native int spiTransactionB(int port, byte[] dataToSend,
-                                           byte[] dataReceived, byte size);
+  public static native int spiTransactionB(
+      int port, byte[] dataToSend, byte[] dataReceived, byte size);
 
   public static native int spiWrite(int port, ByteBuffer dataToSend, byte sendSize);
 
@@ -31,8 +28,8 @@
 
   public static native void spiSetSpeed(int port, int speed);
 
-  public static native void spiSetOpts(int port, int msbFirst, int sampleOnTrailing,
-                                       int clkIdleHigh);
+  public static native void spiSetOpts(
+      int port, int msbFirst, int sampleOnTrailing, int clkIdleHigh);
 
   public static native void spiSetChipSelectActiveHigh(int port);
 
@@ -44,9 +41,12 @@
 
   public static native void spiStartAutoRate(int port, double period);
 
-  public static native void spiStartAutoTrigger(int port, int digitalSourceHandle,
-                                                int analogTriggerType, boolean triggerRising,
-                                                boolean triggerFalling);
+  public static native void spiStartAutoTrigger(
+      int port,
+      int digitalSourceHandle,
+      int analogTriggerType,
+      boolean triggerRising,
+      boolean triggerFalling);
 
   public static native void spiStopAuto(int port);
 
@@ -54,13 +54,14 @@
 
   public static native void spiForceAutoRead(int port);
 
-  public static native int spiReadAutoReceivedData(int port, ByteBuffer buffer, int numToRead,
-                                                   double timeout);
+  public static native int spiReadAutoReceivedData(
+      int port, ByteBuffer buffer, int numToRead, double timeout);
 
-  public static native int spiReadAutoReceivedData(int port, int[] buffer, int numToRead,
-                                                   double timeout);
+  public static native int spiReadAutoReceivedData(
+      int port, int[] buffer, int numToRead, double timeout);
 
   public static native int spiGetAutoDroppedCount(int port);
 
-  public static native void spiConfigureAutoStall(int port, int csToSclkTicks, int stallTicks, int pow2BytesPerRead);
+  public static native void spiConfigureAutoStall(
+      int port, int csToSclkTicks, int stallTicks, int pow2BytesPerRead);
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/SerialPortJNI.java b/hal/src/main/java/edu/wpi/first/hal/SerialPortJNI.java
index 267947b..ee9464e 100644
--- a/hal/src/main/java/edu/wpi/first/hal/SerialPortJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/SerialPortJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/SimBoolean.java b/hal/src/main/java/edu/wpi/first/hal/SimBoolean.java
index 00e8552..3f4c257 100644
--- a/hal/src/main/java/edu/wpi/first/hal/SimBoolean.java
+++ b/hal/src/main/java/edu/wpi/first/hal/SimBoolean.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
-/**
- * A wrapper around a simulator boolean value handle.
- */
+/** A wrapper around a simulator boolean value handle. */
 public class SimBoolean extends SimValue {
   /**
    * Wraps a simulated value handle as returned by SimDeviceJNI.createSimValueBoolean().
diff --git a/hal/src/main/java/edu/wpi/first/hal/SimDevice.java b/hal/src/main/java/edu/wpi/first/hal/SimDevice.java
index ecddc2e..67c39fe 100644
--- a/hal/src/main/java/edu/wpi/first/hal/SimDevice.java
+++ b/hal/src/main/java/edu/wpi/first/hal/SimDevice.java
@@ -1,23 +1,39 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 /**
  * A wrapper around a simulator device handle.
+ *
+ * <p>Teams: if you are using this class, you are likely confusing it for {@link
+ * edu.wpi.first.wpilibj.simulation.SimDeviceSim}.
+ *
+ * <p>Vendors: This class should be used from inside the device class to define the
+ * properties/fields of the device. Use {@link #create} to get a SimDevice object, then use {@link
+ * #createDouble(String, Direction, double)} or similar to define the device's fields. See {@link
+ * edu.wpi.first.wpilibj.ADXRS450_Gyro} for an example implementation.
  */
 public class SimDevice implements AutoCloseable {
+  public enum Direction {
+    kInput(SimDeviceJNI.kInput),
+    kOutput(SimDeviceJNI.kOutput),
+    kBidir(SimDeviceJNI.kBidir);
+
+    public final int m_value;
+
+    Direction(int value) {
+      m_value = value;
+    }
+  }
+
   /**
    * Creates a simulated device.
    *
-   * <p>The device name must be unique.  Returns null if the device name
-   * already exists.  If multiple instances of the same device are desired,
-   * recommend appending the instance/unique identifer in brackets to the base
-   * name, e.g. "device[1]".
+   * <p>The device name must be unique. Returns null if the device name already exists. If multiple
+   * instances of the same device are desired, recommend appending the instance/unique identifer in
+   * brackets to the base name, e.g. "device[1]".
    *
    * <p>null is returned if not in simulation.
    *
@@ -35,10 +51,9 @@
   /**
    * Creates a simulated device.
    *
-   * <p>The device name must be unique.  Returns null if the device name
-   * already exists.  This is a convenience method that appends index in
-   * brackets to the device name, e.g. passing index=1 results in "device[1]"
-   * for the device name.
+   * <p>The device name must be unique. Returns null if the device name already exists. This is a
+   * convenience method that appends index in brackets to the device name, e.g. passing index=1
+   * results in "device[1]" for the device name.
    *
    * <p>null is returned if not in simulation.
    *
@@ -53,10 +68,9 @@
   /**
    * Creates a simulated device.
    *
-   * <p>The device name must be unique.  Returns null if the device name
-   * already exists.  This is a convenience method that appends index and
-   * channel in brackets to the device name, e.g. passing index=1 and channel=2
-   * results in "device[1,2]" for the device name.
+   * <p>The device name must be unique. Returns null if the device name already exists. This is a
+   * convenience method that appends index and channel in brackets to the device name, e.g. passing
+   * index=1 and channel=2 results in "device[1,2]" for the device name.
    *
    * <p>null is returned if not in simulation.
    *
@@ -101,9 +115,25 @@
    * @param readonly if the value should not be written from simulation side
    * @param initialValue initial value
    * @return simulated value object
+   * @deprecated Use direction function instead
    */
+  @Deprecated
   public SimValue createValue(String name, boolean readonly, HALValue initialValue) {
-    int handle = SimDeviceJNI.createSimValue(m_handle, name, readonly, initialValue);
+    return createValue(name, readonly ? Direction.kOutput : Direction.kInput, initialValue);
+  }
+
+  /**
+   * Creates a value on the simulated device.
+   *
+   * <p>Returns null if not in simulation.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated value object
+   */
+  public SimValue createValue(String name, Direction direction, HALValue initialValue) {
+    int handle = SimDeviceJNI.createSimValue(m_handle, name, direction.m_value, initialValue);
     if (handle <= 0) {
       return null;
     }
@@ -111,6 +141,42 @@
   }
 
   /**
+   * Creates an int value on the simulated device.
+   *
+   * <p>Returns null if not in simulation.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated double value object
+   */
+  public SimInt createInt(String name, Direction direction, int initialValue) {
+    int handle = SimDeviceJNI.createSimValueInt(m_handle, name, direction.m_value, initialValue);
+    if (handle <= 0) {
+      return null;
+    }
+    return new SimInt(handle);
+  }
+
+  /**
+   * Creates a long value on the simulated device.
+   *
+   * <p>Returns null if not in simulation.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated double value object
+   */
+  public SimLong createLong(String name, Direction direction, long initialValue) {
+    int handle = SimDeviceJNI.createSimValueLong(m_handle, name, direction.m_value, initialValue);
+    if (handle <= 0) {
+      return null;
+    }
+    return new SimLong(handle);
+  }
+
+  /**
    * Creates a double value on the simulated device.
    *
    * <p>Returns null if not in simulation.
@@ -119,9 +185,25 @@
    * @param readonly if the value should not be written from simulation side
    * @param initialValue initial value
    * @return simulated double value object
+   * @deprecated Use direction function instead
    */
+  @Deprecated
   public SimDouble createDouble(String name, boolean readonly, double initialValue) {
-    int handle = SimDeviceJNI.createSimValueDouble(m_handle, name, readonly, initialValue);
+    return createDouble(name, readonly ? Direction.kOutput : Direction.kInput, initialValue);
+  }
+
+  /**
+   * Creates a double value on the simulated device.
+   *
+   * <p>Returns null if not in simulation.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated double value object
+   */
+  public SimDouble createDouble(String name, Direction direction, double initialValue) {
+    int handle = SimDeviceJNI.createSimValueDouble(m_handle, name, direction.m_value, initialValue);
     if (handle <= 0) {
       return null;
     }
@@ -140,9 +222,54 @@
    * @param options array of option descriptions
    * @param initialValue initial value (selection)
    * @return simulated enum value object
+   * @deprecated Use direction function instead
    */
+  @Deprecated
   public SimEnum createEnum(String name, boolean readonly, String[] options, int initialValue) {
-    int handle = SimDeviceJNI.createSimValueEnum(m_handle, name, readonly, options, initialValue);
+    return createEnum(name, readonly ? Direction.kOutput : Direction.kInput, options, initialValue);
+  }
+
+  /**
+   * Creates an enumerated value on the simulated device.
+   *
+   * <p>Enumerated values are always in the range 0 to numOptions-1.
+   *
+   * <p>Returns null if not in simulation.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param options array of option descriptions
+   * @param initialValue initial value (selection)
+   * @return simulated enum value object
+   */
+  public SimEnum createEnum(String name, Direction direction, String[] options, int initialValue) {
+    int handle =
+        SimDeviceJNI.createSimValueEnum(m_handle, name, direction.m_value, options, initialValue);
+    if (handle <= 0) {
+      return null;
+    }
+    return new SimEnum(handle);
+  }
+
+  /**
+   * Creates an enumerated value on the simulated device with double values.
+   *
+   * <p>Enumerated values are always in the range 0 to numOptions-1.
+   *
+   * <p>Returns null if not in simulation.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param options array of option descriptions
+   * @param optionValues array of option values (must be the same size as options)
+   * @param initialValue initial value (selection)
+   * @return simulated enum value object
+   */
+  public SimEnum createEnumDouble(
+      String name, Direction direction, String[] options, double[] optionValues, int initialValue) {
+    int handle =
+        SimDeviceJNI.createSimValueEnumDouble(
+            m_handle, name, direction.m_value, options, optionValues, initialValue);
     if (handle <= 0) {
       return null;
     }
@@ -158,9 +285,26 @@
    * @param readonly if the value should not be written from simulation side
    * @param initialValue initial value
    * @return simulated boolean value object
+   * @deprecated Use direction function instead
    */
+  @Deprecated
   public SimBoolean createBoolean(String name, boolean readonly, boolean initialValue) {
-    int handle = SimDeviceJNI.createSimValueBoolean(m_handle, name, readonly, initialValue);
+    return createBoolean(name, readonly ? Direction.kOutput : Direction.kInput, initialValue);
+  }
+
+  /**
+   * Creates a boolean value on the simulated device.
+   *
+   * <p>Returns null if not in simulation.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated boolean value object
+   */
+  public SimBoolean createBoolean(String name, Direction direction, boolean initialValue) {
+    int handle =
+        SimDeviceJNI.createSimValueBoolean(m_handle, name, direction.m_value, initialValue);
     if (handle <= 0) {
       return null;
     }
diff --git a/hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java b/hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java
index d9b8931..4279916 100644
--- a/hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java
@@ -1,20 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
 public class SimDeviceJNI extends JNIWrapper {
+  public static final int kInput = 0;
+  public static final int kOutput = 1;
+  public static final int kBidir = 2;
+
   /**
    * Creates a simulated device.
    *
-   * <p>The device name must be unique.  0 is returned if the device name
-   * already exists.  If multiple instances of the same device are desired,
-   * recommend appending the instance/unique identifer in brackets to the base
-   * name, e.g. "device[1]".
+   * <p>The device name must be unique. 0 is returned if the device name already exists. If multiple
+   * instances of the same device are desired, recommend appending the instance/unique identifer in
+   * brackets to the base name, e.g. "device[1]".
    *
    * <p>0 is returned if not in simulation.
    *
@@ -26,49 +26,124 @@
   /**
    * Frees a simulated device.
    *
-   * <p>This also allows the same device name to be used again.
-   * This also frees all the simulated values created on the device.
+   * <p>This also allows the same device name to be used again. This also frees all the simulated
+   * values created on the device.
    *
    * @param handle simulated device handle
    */
   public static native void freeSimDevice(int handle);
 
-  private static native int createSimValueNative(int device, String name, boolean readonly,
-      int type, long value1, double value2);
+  private static native int createSimValueNative(
+      int device, String name, int direction, int type, long value1, double value2);
 
   /**
    * Creates a value on a simulated device.
    *
-   * <p>Returns 0 if not in simulation; this can be used to avoid calls
-   * to Set/Get functions.
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
    *
    * @param device simulated device handle
    * @param name value name
    * @param readonly if the value should not be written from simulation side
    * @param initialValue initial value
    * @return simulated value handle
+   * @deprecated Use direction-taking function instead
    */
-  public static int createSimValue(int device, String name, boolean readonly,
-      HALValue initialValue) {
-    return createSimValueNative(device, name, readonly, initialValue.getType(),
-        initialValue.getNativeLong(), initialValue.getNativeDouble());
+  @Deprecated
+  public static int createSimValue(
+      int device, String name, boolean readonly, HALValue initialValue) {
+    return createSimValueNative(
+        device,
+        name,
+        readonly ? kOutput : kInput,
+        initialValue.getType(),
+        initialValue.getNativeLong(),
+        initialValue.getNativeDouble());
+  }
+
+  /**
+   * Creates a value on a simulated device.
+   *
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
+   *
+   * @param device simulated device handle
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated value handle
+   */
+  public static int createSimValue(int device, String name, int direction, HALValue initialValue) {
+    return createSimValueNative(
+        device,
+        name,
+        direction,
+        initialValue.getType(),
+        initialValue.getNativeLong(),
+        initialValue.getNativeDouble());
+  }
+
+  /**
+   * Creates an int value on a simulated device.
+   *
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
+   *
+   * @param device simulated device handle
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated value handle
+   */
+  public static int createSimValueInt(int device, String name, int direction, int initialValue) {
+    return createSimValueNative(device, name, direction, HALValue.kInt, initialValue, 0.0);
+  }
+
+  /**
+   * Creates a long value on a simulated device.
+   *
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
+   *
+   * @param device simulated device handle
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated value handle
+   */
+  public static int createSimValueLong(int device, String name, int direction, long initialValue) {
+    return createSimValueNative(device, name, direction, HALValue.kLong, initialValue, 0.0);
   }
 
   /**
    * Creates a double value on a simulated device.
    *
-   * <p>Returns 0 if not in simulation; this can be used to avoid calls
-   * to Set/Get functions.
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
    *
    * @param device simulated device handle
    * @param name value name
    * @param readonly if the value should not be written from simulation side
    * @param initialValue initial value
    * @return simulated value handle
+   * @deprecated Use direction-taking function instead
    */
-  public static int createSimValueDouble(int device, String name, boolean readonly,
-      double initialValue) {
-    return createSimValueNative(device, name, readonly, HALValue.kDouble, 0, initialValue);
+  @Deprecated
+  public static int createSimValueDouble(
+      int device, String name, boolean readonly, double initialValue) {
+    return createSimValueNative(
+        device, name, readonly ? kOutput : kInput, HALValue.kDouble, 0, initialValue);
+  }
+
+  /**
+   * Creates a double value on a simulated device.
+   *
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
+   *
+   * @param device simulated device handle
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated value handle
+   */
+  public static int createSimValueDouble(
+      int device, String name, int direction, double initialValue) {
+    return createSimValueNative(device, name, direction, HALValue.kDouble, 0, initialValue);
   }
 
   /**
@@ -76,8 +151,7 @@
    *
    * <p>Enumerated values are always in the range 0 to numOptions-1.
    *
-   * <p>Returns 0 if not in simulation; this can be used to avoid calls
-   * to Set/Get functions.
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
    *
    * @param device simulated device handle
    * @param name value name
@@ -85,26 +159,88 @@
    * @param options array of option descriptions
    * @param initialValue initial value (selection)
    * @return simulated value handle
+   * @deprecated Use direction-taking function instead
    */
-  public static native int createSimValueEnum(int device, String name, boolean readonly,
-      String[] options, int initialValue);
+  @Deprecated
+  public static int createSimValueEnum(
+      int device, String name, boolean readonly, String[] options, int initialValue) {
+    return createSimValueEnum(device, name, readonly ? kOutput : kInput, options, initialValue);
+  }
+
+  /**
+   * Creates an enumerated value on a simulated device.
+   *
+   * <p>Enumerated values are always in the range 0 to numOptions-1.
+   *
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
+   *
+   * @param device simulated device handle
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param options array of option descriptions
+   * @param initialValue initial value (selection)
+   * @return simulated value handle
+   */
+  public static native int createSimValueEnum(
+      int device, String name, int direction, String[] options, int initialValue);
+
+  /**
+   * Creates an enumerated value on a simulated device with double values.
+   *
+   * <p>Enumerated values are always in the range 0 to numOptions-1.
+   *
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
+   *
+   * @param device simulated device handle
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param options array of option descriptions
+   * @param optionValues array of option values (must be the same size as options)
+   * @param initialValue initial value (selection)
+   * @return simulated value handle
+   */
+  public static native int createSimValueEnumDouble(
+      int device,
+      String name,
+      int direction,
+      String[] options,
+      double[] optionValues,
+      int initialValue);
 
   /**
    * Creates a boolean value on a simulated device.
    *
-   * <p>Returns 0 if not in simulation; this can be used to avoid calls
-   * to Set/Get functions.
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
    *
    * @param device simulated device handle
    * @param name value name
    * @param readonly if the value should not be written from simulation side
    * @param initialValue initial value
    * @return simulated value handle
+   * @deprecated Use direction-taking function instead
    */
-  public static int createSimValueBoolean(int device, String name, boolean readonly,
-      boolean initialValue) {
-    return createSimValueNative(device, name, readonly, HALValue.kBoolean,
-        initialValue ? 1 : 0, 0.0);
+  @Deprecated
+  public static int createSimValueBoolean(
+      int device, String name, boolean readonly, boolean initialValue) {
+    return createSimValueNative(
+        device, name, readonly ? kOutput : kInput, HALValue.kBoolean, initialValue ? 1 : 0, 0.0);
+  }
+
+  /**
+   * Creates a boolean value on a simulated device.
+   *
+   * <p>Returns 0 if not in simulation; this can be used to avoid calls to Set/Get functions.
+   *
+   * @param device simulated device handle
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated value handle
+   */
+  public static int createSimValueBoolean(
+      int device, String name, int direction, boolean initialValue) {
+    return createSimValueNative(
+        device, name, direction, HALValue.kBoolean, initialValue ? 1 : 0, 0.0);
   }
 
   /**
@@ -116,6 +252,22 @@
   public static native HALValue getSimValue(int handle);
 
   /**
+   * Gets a simulated value (int).
+   *
+   * @param handle simulated value handle
+   * @return The current value
+   */
+  public static native int getSimValueInt(int handle);
+
+  /**
+   * Gets a simulated value (long).
+   *
+   * @param handle simulated value handle
+   * @return The current value
+   */
+  public static native long getSimValueLong(int handle);
+
+  /**
    * Gets a simulated value (double).
    *
    * @param handle simulated value handle
@@ -152,6 +304,26 @@
   }
 
   /**
+   * Sets a simulated value (int).
+   *
+   * @param handle simulated value handle
+   * @param value the value to set
+   */
+  public static void setSimValueInt(int handle, int value) {
+    setSimValueNative(handle, HALValue.kInt, value, 0.0);
+  }
+
+  /**
+   * Sets a simulated value (long).
+   *
+   * @param handle simulated value handle
+   * @param value the value to set
+   */
+  public static void setSimValueLong(int handle, long value) {
+    setSimValueNative(handle, HALValue.kLong, value, 0.0);
+  }
+
+  /**
    * Sets a simulated value (double).
    *
    * @param handle simulated value handle
@@ -180,4 +352,13 @@
   public static void setSimValueBoolean(int handle, boolean value) {
     setSimValueNative(handle, HALValue.kBoolean, value ? 1 : 0, 0.0);
   }
+
+  /**
+   * Resets a simulated double or integral value to 0. Has no effect on other value types. Use this
+   * instead of Set(0) for resetting incremental sensor values like encoder counts or gyro
+   * accumulated angle to ensure correct behavior in a distributed system (e.g. WebSockets).
+   *
+   * @param handle simulated value handle
+   */
+  public static native void resetSimValue(int handle);
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/SimDouble.java b/hal/src/main/java/edu/wpi/first/hal/SimDouble.java
index 51c9789..508208f 100644
--- a/hal/src/main/java/edu/wpi/first/hal/SimDouble.java
+++ b/hal/src/main/java/edu/wpi/first/hal/SimDouble.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
-/**
- * A wrapper around a simulator double value handle.
- */
+/** A wrapper around a simulator double value handle. */
 public class SimDouble extends SimValue {
   /**
    * Wraps a simulated value handle as returned by SimDeviceJNI.createSimValueDouble().
@@ -37,4 +32,13 @@
   public void set(double value) {
     SimDeviceJNI.setSimValueDouble(m_handle, value);
   }
+
+  /**
+   * Resets the simulated value to 0. Use this instead of Set(0) for resetting incremental sensor
+   * values like encoder counts or gyro accumulated angle to ensure correct behavior in a
+   * distributed system (e.g. WebSockets).
+   */
+  public void reset() {
+    SimDeviceJNI.resetSimValue(m_handle);
+  }
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/SimEnum.java b/hal/src/main/java/edu/wpi/first/hal/SimEnum.java
index d951bed..78f963d 100644
--- a/hal/src/main/java/edu/wpi/first/hal/SimEnum.java
+++ b/hal/src/main/java/edu/wpi/first/hal/SimEnum.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
-/**
- * A wrapper around a simulator enum value handle.
- */
+/** A wrapper around a simulator enum value handle. */
 public class SimEnum extends SimValue {
   /**
    * Wraps a simulated value handle as returned by SimDeviceJNI.createSimValueEnum().
diff --git a/hal/src/main/java/edu/wpi/first/hal/SimInt.java b/hal/src/main/java/edu/wpi/first/hal/SimInt.java
new file mode 100644
index 0000000..f2d30eb
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/SimInt.java
@@ -0,0 +1,44 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.hal;
+
+/** A wrapper around a simulator int value handle. */
+public class SimInt extends SimValue {
+  /**
+   * Wraps a simulated value handle as returned by SimDeviceJNI.createSimValueInt().
+   *
+   * @param handle simulated value handle
+   */
+  public SimInt(int handle) {
+    super(handle);
+  }
+
+  /**
+   * Gets the simulated value.
+   *
+   * @return The current value
+   */
+  public int get() {
+    return SimDeviceJNI.getSimValueInt(m_handle);
+  }
+
+  /**
+   * Sets the simulated value.
+   *
+   * @param value the value to set
+   */
+  public void set(int value) {
+    SimDeviceJNI.setSimValueInt(m_handle, value);
+  }
+
+  /**
+   * Resets the simulated value to 0. Use this instead of Set(0) for resetting incremental sensor
+   * values like encoder counts or gyro accumulated angle to ensure correct behavior in a
+   * distributed system (e.g. WebSockets).
+   */
+  public void reset() {
+    SimDeviceJNI.resetSimValue(m_handle);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/SimLong.java b/hal/src/main/java/edu/wpi/first/hal/SimLong.java
new file mode 100644
index 0000000..80ad963
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/SimLong.java
@@ -0,0 +1,44 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.hal;
+
+/** A wrapper around a simulator long value handle. */
+public class SimLong extends SimValue {
+  /**
+   * Wraps a simulated value handle as returned by SimDeviceJNI.createSimValueLong().
+   *
+   * @param handle simulated value handle
+   */
+  public SimLong(int handle) {
+    super(handle);
+  }
+
+  /**
+   * Gets the simulated value.
+   *
+   * @return The current value
+   */
+  public long get() {
+    return SimDeviceJNI.getSimValueLong(m_handle);
+  }
+
+  /**
+   * Sets the simulated value.
+   *
+   * @param value the value to set
+   */
+  public void set(long value) {
+    SimDeviceJNI.setSimValueLong(m_handle, value);
+  }
+
+  /**
+   * Resets the simulated value to 0. Use this instead of Set(0) for resetting incremental sensor
+   * values like encoder counts or gyro accumulated angle to ensure correct behavior in a
+   * distributed system (e.g. WebSockets).
+   */
+  public void reset() {
+    SimDeviceJNI.resetSimValue(m_handle);
+  }
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/SimValue.java b/hal/src/main/java/edu/wpi/first/hal/SimValue.java
index 05d6b0c..a486981 100644
--- a/hal/src/main/java/edu/wpi/first/hal/SimValue.java
+++ b/hal/src/main/java/edu/wpi/first/hal/SimValue.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal;
 
-/**
- * A wrapper around a simulator value handle.
- */
+/** A wrapper around a simulator value handle. */
 public class SimValue {
   /**
    * Wraps a simulated value handle as returned by SimDeviceJNI.createSimValue().
diff --git a/hal/src/main/java/edu/wpi/first/hal/SolenoidJNI.java b/hal/src/main/java/edu/wpi/first/hal/SolenoidJNI.java
deleted file mode 100644
index 66acbea..0000000
--- a/hal/src/main/java/edu/wpi/first/hal/SolenoidJNI.java
+++ /dev/null
@@ -1,36 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.hal;
-
-public class SolenoidJNI extends JNIWrapper {
-  public static native int initializeSolenoidPort(int halPortHandle);
-
-  public static native boolean checkSolenoidModule(int module);
-
-  public static native boolean checkSolenoidChannel(int channel);
-
-  public static native void freeSolenoidPort(int portHandle);
-
-  public static native void setSolenoid(int portHandle, boolean on);
-
-  public static native boolean getSolenoid(int portHandle);
-
-  public static native int getAllSolenoids(int module);
-
-  public static native int getPCMSolenoidBlackList(int module);
-
-  public static native boolean getPCMSolenoidVoltageStickyFault(int module);
-
-  public static native boolean getPCMSolenoidVoltageFault(int module);
-
-  public static native void clearAllPCMStickyFaults(int module);
-
-  public static native void setOneShotDuration(int portHandle, long durationMS);
-
-  public static native void fireOneShot(int portHandle);
-}
diff --git a/hal/src/main/java/edu/wpi/first/hal/ThreadsJNI.java b/hal/src/main/java/edu/wpi/first/hal/ThreadsJNI.java
index e320eb5..c854e20 100644
--- a/hal/src/main/java/edu/wpi/first/hal/ThreadsJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/ThreadsJNI.java
@@ -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.
 
 package edu.wpi.first.hal;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANExceptionFactory.java b/hal/src/main/java/edu/wpi/first/hal/can/CANExceptionFactory.java
index dc089f8..3c0a4b9 100644
--- a/hal/src/main/java/edu/wpi/first/hal/can/CANExceptionFactory.java
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANExceptionFactory.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.can;
 
@@ -17,9 +14,10 @@
   static final int ERR_CANSessionMux_NotAllowed = -44088;
   static final int ERR_CANSessionMux_NotInitialized = -44089;
 
-  @SuppressWarnings({"JavadocMethod", "PMD.CyclomaticComplexity"})
-  public static void checkStatus(int status, int messageID) throws CANInvalidBufferException,
-      CANMessageNotAllowedException, CANNotInitializedException, UncleanStatusException {
+  @SuppressWarnings("MissingJavadocMethod")
+  public static void checkStatus(int status, int messageID)
+      throws CANInvalidBufferException, CANMessageNotAllowedException, CANNotInitializedException,
+          UncleanStatusException {
     switch (status) {
       case NIRioStatus.kRioStatusSuccess:
         // Everything is ok... don't throw.
@@ -41,7 +39,5 @@
     }
   }
 
-  private CANExceptionFactory() {
-
-  }
+  private CANExceptionFactory() {}
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANInvalidBufferException.java b/hal/src/main/java/edu/wpi/first/hal/can/CANInvalidBufferException.java
index 8ea718b..ef2fa0d 100644
--- a/hal/src/main/java/edu/wpi/first/hal/can/CANInvalidBufferException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANInvalidBufferException.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.can;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANJNI.java b/hal/src/main/java/edu/wpi/first/hal/can/CANJNI.java
index 754157b..b4f344f 100644
--- a/hal/src/main/java/edu/wpi/first/hal/can/CANJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANJNI.java
@@ -1,17 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.can;
 
+import edu.wpi.first.hal.JNIWrapper;
 import java.nio.ByteBuffer;
 import java.nio.IntBuffer;
 
-import edu.wpi.first.hal.JNIWrapper;
-
 @SuppressWarnings("AbbreviationAsWordInName")
 public class CANJNI extends JNIWrapper {
   public static final int CAN_SEND_PERIOD_NO_REPEAT = 0;
@@ -22,15 +18,13 @@
   public static final int CAN_IS_FRAME_11BIT = 0x40000000;
 
   @SuppressWarnings("MethodName")
-  public static native void FRCNetCommCANSessionMuxSendMessage(int messageID,
-                                                               byte[] data,
-                                                               int periodMs);
+  public static native void FRCNetCommCANSessionMuxSendMessage(
+      int messageID, byte[] data, int periodMs);
 
   @SuppressWarnings("MethodName")
   public static native byte[] FRCNetCommCANSessionMuxReceiveMessage(
       IntBuffer messageID, int messageIDMask, ByteBuffer timeStamp);
 
-
   @SuppressWarnings("MethodName")
-  public static native void GetCANStatus(CANStatus status);
+  public static native void getCANStatus(CANStatus status);
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotAllowedException.java b/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotAllowedException.java
index f4ba6a8..de7a70a 100644
--- a/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotAllowedException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotAllowedException.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.can;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotFoundException.java b/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotFoundException.java
index 0838691..39eab14 100644
--- a/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotFoundException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANMessageNotFoundException.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.can;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANNotInitializedException.java b/hal/src/main/java/edu/wpi/first/hal/can/CANNotInitializedException.java
index 119b59d..30f139d 100644
--- a/hal/src/main/java/edu/wpi/first/hal/can/CANNotInitializedException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANNotInitializedException.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.can;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/can/CANStatus.java b/hal/src/main/java/edu/wpi/first/hal/can/CANStatus.java
index 492d999..62df8e8 100644
--- a/hal/src/main/java/edu/wpi/first/hal/can/CANStatus.java
+++ b/hal/src/main/java/edu/wpi/first/hal/can/CANStatus.java
@@ -1,49 +1,38 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.can;
 
-/**
- * Structure for holding the result of a CAN Status request.
- */
+/** Structure for holding the result of a CAN Status request. */
 public class CANStatus {
-  /**
-   * The utilization of the CAN Bus.
-   */
+  /** The utilization of the CAN Bus. */
   @SuppressWarnings("MemberName")
   public double percentBusUtilization;
 
-  /**
-   * The CAN Bus off count.
-   */
+  /** The CAN Bus off count. */
   @SuppressWarnings("MemberName")
   public int busOffCount;
 
-  /**
-   * The CAN Bus TX full count.
-   */
+  /** The CAN Bus TX full count. */
   @SuppressWarnings("MemberName")
   public int txFullCount;
 
-  /**
-   * The CAN Bus receive error count.
-   */
+  /** The CAN Bus receive error count. */
   @SuppressWarnings("MemberName")
   public int receiveErrorCount;
 
-  /**
-   * The CAN Bus transmit error count.
-   */
+  /** The CAN Bus transmit error count. */
   @SuppressWarnings("MemberName")
   public int transmitErrorCount;
 
-  @SuppressWarnings("JavadocMethod")
-  public void setStatus(double percentBusUtilization, int busOffCount, int txFullCount,
-                        int receiveErrorCount, int transmitErrorCount) {
+  @SuppressWarnings("MissingJavadocMethod")
+  public void setStatus(
+      double percentBusUtilization,
+      int busOffCount,
+      int txFullCount,
+      int receiveErrorCount,
+      int transmitErrorCount) {
     this.percentBusUtilization = percentBusUtilization;
     this.busOffCount = busOffCount;
     this.txFullCount = txFullCount;
diff --git a/hal/src/main/java/edu/wpi/first/hal/communication/NIRioStatus.java b/hal/src/main/java/edu/wpi/first/hal/communication/NIRioStatus.java
index f49f34e..ad17a3e 100644
--- a/hal/src/main/java/edu/wpi/first/hal/communication/NIRioStatus.java
+++ b/hal/src/main/java/edu/wpi/first/hal/communication/NIRioStatus.java
@@ -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.
 
 package edu.wpi.first.hal.communication;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/AccelerometerDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/AccelerometerDataJNI.java
index cb42c98..5ea3726 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/AccelerometerDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/AccelerometerDataJNI.java
@@ -1,38 +1,55 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class AccelerometerDataJNI extends JNIWrapper {
-  public static native int registerActiveCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerActiveCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelActiveCallback(int index, int uid);
+
   public static native boolean getActive(int index);
+
   public static native void setActive(int index, boolean active);
 
-  public static native int registerRangeCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerRangeCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelRangeCallback(int index, int uid);
+
   public static native int getRange(int index);
+
   public static native void setRange(int index, int range);
 
-  public static native int registerXCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerXCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelXCallback(int index, int uid);
+
   public static native double getX(int index);
+
   public static native void setX(int index, double x);
 
-  public static native int registerYCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerYCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelYCallback(int index, int uid);
+
   public static native double getY(int index);
+
   public static native void setY(int index, double y);
 
-  public static native int registerZCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerZCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelZCallback(int index, int uid);
+
   public static native double getZ(int index);
+
   public static native void setZ(int index, double z);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/AddressableLEDDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/AddressableLEDDataJNI.java
index 0aa4d47..8ba0e94 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/AddressableLEDDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/AddressableLEDDataJNI.java
@@ -1,38 +1,54 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class AddressableLEDDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
-  public static native int registerOutputPortCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerOutputPortCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelOutputPortCallback(int index, int uid);
+
   public static native int getOutputPort(int index);
+
   public static native void setOutputPort(int index, int outputPort);
 
-  public static native int registerLengthCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerLengthCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelLengthCallback(int index, int uid);
+
   public static native int getLength(int index);
+
   public static native void setLength(int index, int length);
 
-  public static native int registerRunningCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerRunningCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelRunningCallback(int index, int uid);
+
   public static native boolean getRunning(int index);
+
   public static native void setRunning(int index, boolean running);
 
   public static native int registerDataCallback(int index, ConstBufferCallback callback);
+
   public static native void cancelDataCallback(int index, int uid);
+
   public static native byte[] getData(int index);
+
   public static native void setData(int index, byte[] data);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogGyroDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogGyroDataJNI.java
index 42cc508..a6acc9a 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogGyroDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogGyroDataJNI.java
@@ -1,28 +1,37 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class AnalogGyroDataJNI extends JNIWrapper {
-  public static native int registerAngleCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerAngleCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAngleCallback(int index, int uid);
+
   public static native double getAngle(int index);
+
   public static native void setAngle(int index, double angle);
 
-  public static native int registerRateCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerRateCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelRateCallback(int index, int uid);
+
   public static native double getRate(int index);
+
   public static native void setRate(int index, double rate);
 
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogInDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogInDataJNI.java
index 3656ffa..4229c09 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogInDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogInDataJNI.java
@@ -1,58 +1,91 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class AnalogInDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
-  public static native int registerAverageBitsCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerAverageBitsCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAverageBitsCallback(int index, int uid);
+
   public static native int getAverageBits(int index);
+
   public static native void setAverageBits(int index, int averageBits);
 
-  public static native int registerOversampleBitsCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerOversampleBitsCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelOversampleBitsCallback(int index, int uid);
+
   public static native int getOversampleBits(int index);
+
   public static native void setOversampleBits(int index, int oversampleBits);
 
-  public static native int registerVoltageCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerVoltageCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelVoltageCallback(int index, int uid);
+
   public static native double getVoltage(int index);
+
   public static native void setVoltage(int index, double voltage);
 
-  public static native int registerAccumulatorInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerAccumulatorInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAccumulatorInitializedCallback(int index, int uid);
+
   public static native boolean getAccumulatorInitialized(int index);
+
   public static native void setAccumulatorInitialized(int index, boolean accumulatorInitialized);
 
-  public static native int registerAccumulatorValueCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerAccumulatorValueCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAccumulatorValueCallback(int index, int uid);
+
   public static native long getAccumulatorValue(int index);
+
   public static native void setAccumulatorValue(int index, long accumulatorValue);
 
-  public static native int registerAccumulatorCountCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerAccumulatorCountCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAccumulatorCountCallback(int index, int uid);
+
   public static native long getAccumulatorCount(int index);
+
   public static native void setAccumulatorCount(int index, long accumulatorCount);
 
-  public static native int registerAccumulatorCenterCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerAccumulatorCenterCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAccumulatorCenterCallback(int index, int uid);
+
   public static native int getAccumulatorCenter(int index);
+
   public static native void setAccumulatorCenter(int index, int AccumulatorCenter);
 
-  public static native int registerAccumulatorDeadbandCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerAccumulatorDeadbandCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAccumulatorDeadbandCallback(int index, int uid);
+
   public static native int getAccumulatorDeadband(int index);
+
   public static native void setAccumulatorDeadband(int index, int AccumulatorDeadband);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogOutDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogOutDataJNI.java
index 23bc8ac..6af16a0 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogOutDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogOutDataJNI.java
@@ -1,23 +1,28 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class AnalogOutDataJNI extends JNIWrapper {
-  public static native int registerVoltageCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerVoltageCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelVoltageCallback(int index, int uid);
+
   public static native double getVoltage(int index);
+
   public static native void setVoltage(int index, double voltage);
 
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogTriggerDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogTriggerDataJNI.java
index ca89a28..67b65b5 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogTriggerDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/AnalogTriggerDataJNI.java
@@ -1,28 +1,37 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class AnalogTriggerDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
-  public static native int registerTriggerLowerBoundCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerTriggerLowerBoundCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelTriggerLowerBoundCallback(int index, int uid);
+
   public static native double getTriggerLowerBound(int index);
+
   public static native void setTriggerLowerBound(int index, double triggerLowerBound);
 
-  public static native int registerTriggerUpperBoundCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerTriggerUpperBoundCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelTriggerUpperBoundCallback(int index, int uid);
+
   public static native double getTriggerUpperBound(int index);
+
   public static native void setTriggerUpperBound(int index, double triggerUpperBound);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/BufferCallback.java b/hal/src/main/java/edu/wpi/first/hal/simulation/BufferCallback.java
index a8d8ce1..e93a921 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/BufferCallback.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/BufferCallback.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/CTREPCMDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/CTREPCMDataJNI.java
new file mode 100644
index 0000000..9f60e7e
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/CTREPCMDataJNI.java
@@ -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.
+
+package edu.wpi.first.hal.simulation;
+
+import edu.wpi.first.hal.JNIWrapper;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class CTREPCMDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelInitializedCallback(int index, int uid);
+
+  public static native boolean getInitialized(int index);
+
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerSolenoidOutputCallback(
+      int index, int channel, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelSolenoidOutputCallback(int index, int channel, int uid);
+
+  public static native boolean getSolenoidOutput(int index, int channel);
+
+  public static native void setSolenoidOutput(int index, int channel, boolean solenoidOutput);
+
+  public static native int registerCompressorOnCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelCompressorOnCallback(int index, int uid);
+
+  public static native boolean getCompressorOn(int index);
+
+  public static native void setCompressorOn(int index, boolean compressorOn);
+
+  public static native int registerClosedLoopEnabledCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelClosedLoopEnabledCallback(int index, int uid);
+
+  public static native boolean getClosedLoopEnabled(int index);
+
+  public static native void setClosedLoopEnabled(int index, boolean closeLoopEnabled);
+
+  public static native int registerPressureSwitchCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelPressureSwitchCallback(int index, int uid);
+
+  public static native boolean getPressureSwitch(int index);
+
+  public static native void setPressureSwitch(int index, boolean pressureSwitch);
+
+  public static native int registerCompressorCurrentCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelCompressorCurrentCallback(int index, int uid);
+
+  public static native double getCompressorCurrent(int index);
+
+  public static native void setCompressorCurrent(int index, double compressorCurrent);
+
+  public static native void registerAllNonSolenoidCallbacks(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void registerAllSolenoidCallbacks(
+      int index, int channel, NotifyCallback callback, boolean initialNotify);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/ConstBufferCallback.java b/hal/src/main/java/edu/wpi/first/hal/simulation/ConstBufferCallback.java
index 6cb2375..9e88ec3 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/ConstBufferCallback.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/ConstBufferCallback.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/DIODataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/DIODataJNI.java
index 5d41a2f..0c59415 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/DIODataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/DIODataJNI.java
@@ -1,38 +1,55 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class DIODataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
-  public static native int registerValueCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerValueCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelValueCallback(int index, int uid);
+
   public static native boolean getValue(int index);
+
   public static native void setValue(int index, boolean value);
 
-  public static native int registerPulseLengthCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerPulseLengthCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelPulseLengthCallback(int index, int uid);
+
   public static native double getPulseLength(int index);
+
   public static native void setPulseLength(int index, double pulseLength);
 
-  public static native int registerIsInputCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerIsInputCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelIsInputCallback(int index, int uid);
+
   public static native boolean getIsInput(int index);
+
   public static native void setIsInput(int index, boolean isInput);
 
-  public static native int registerFilterIndexCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerFilterIndexCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelFilterIndexCallback(int index, int uid);
+
   public static native int getFilterIndex(int index);
+
   public static native void setFilterIndex(int index, int filterIndex);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/DigitalPWMDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/DigitalPWMDataJNI.java
index 4e2709f..addcffc 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/DigitalPWMDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/DigitalPWMDataJNI.java
@@ -1,28 +1,37 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class DigitalPWMDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
-  public static native int registerDutyCycleCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerDutyCycleCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelDutyCycleCallback(int index, int uid);
+
   public static native double getDutyCycle(int index);
+
   public static native void setDutyCycle(int index, double dutyCycle);
 
-  public static native int registerPinCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerPinCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelPinCallback(int index, int uid);
+
   public static native int getPin(int index);
+
   public static native void setPin(int index, int pin);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/DriverStationDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/DriverStationDataJNI.java
index a1046c5..196f017 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/DriverStationDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/DriverStationDataJNI.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
@@ -11,76 +8,129 @@
 
 public class DriverStationDataJNI extends JNIWrapper {
   public static native int registerEnabledCallback(NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelEnabledCallback(int uid);
+
   public static native boolean getEnabled();
+
   public static native void setEnabled(boolean enabled);
 
-  public static native int registerAutonomousCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerAutonomousCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAutonomousCallback(int uid);
+
   public static native boolean getAutonomous();
+
   public static native void setAutonomous(boolean autonomous);
 
   public static native int registerTestCallback(NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelTestCallback(int uid);
+
   public static native boolean getTest();
+
   public static native void setTest(boolean test);
 
   public static native int registerEStopCallback(NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelEStopCallback(int uid);
+
   public static native boolean getEStop();
+
   public static native void setEStop(boolean eStop);
 
-  public static native int registerFmsAttachedCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerFmsAttachedCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelFmsAttachedCallback(int uid);
+
   public static native boolean getFmsAttached();
+
   public static native void setFmsAttached(boolean fmsAttached);
 
-  public static native int registerDsAttachedCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerDsAttachedCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelDsAttachedCallback(int uid);
+
   public static native boolean getDsAttached();
+
   public static native void setDsAttached(boolean dsAttached);
 
-  public static native int registerAllianceStationIdCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerAllianceStationIdCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelAllianceStationIdCallback(int uid);
+
   public static native int getAllianceStationId();
+
   public static native void setAllianceStationId(int allianceStationId);
 
-  public static native int registerMatchTimeCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerMatchTimeCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelMatchTimeCallback(int uid);
+
   public static native double getMatchTime();
+
   public static native void setMatchTime(double matchTime);
 
   public static native void setJoystickAxes(byte joystickNum, float[] axesArray);
+
   public static native void setJoystickPOVs(byte joystickNum, short[] povsArray);
+
   public static native void setJoystickButtons(byte joystickNum, int buttons, int count);
+
   public static native long getJoystickOutputs(int stick);
+
   public static native int getJoystickRumble(int stick, int rumbleNum);
 
-  public static native void setMatchInfo(String eventName, String gameSpecificMessage, int matchNumber, int replayNumber, int matchType);
+  public static native void setMatchInfo(
+      String eventName,
+      String gameSpecificMessage,
+      int matchNumber,
+      int replayNumber,
+      int matchType);
 
   public static native void registerAllCallbacks(NotifyCallback callback, boolean initialNotify);
+
   public static native void notifyNewData();
 
   public static native void setSendError(boolean shouldSend);
+
   public static native void setSendConsoleLine(boolean shouldSend);
 
   public static native void setJoystickButton(int stick, int button, boolean state);
+
   public static native void setJoystickAxis(int stick, int axis, double value);
+
   public static native void setJoystickPOV(int stick, int pov, int value);
+
   public static native void setJoystickButtonsValue(int stick, int buttons);
+
   public static native void setJoystickAxisCount(int stick, int count);
+
   public static native void setJoystickPOVCount(int stick, int count);
+
   public static native void setJoystickButtonCount(int stick, int count);
 
   public static native void setJoystickIsXbox(int stick, boolean isXbox);
+
   public static native void setJoystickType(int stick, int type);
+
   public static native void setJoystickName(int stick, String name);
+
   public static native void setJoystickAxisType(int stick, int axis, int type);
 
   public static native void setGameSpecificMessage(String message);
+
   public static native void setEventName(String name);
+
   public static native void setMatchType(int type);
+
   public static native void setMatchNumber(int matchNumber);
+
   public static native void setReplayNumber(int replayNumber);
 
   public static native void resetData();
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/DutyCycleDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/DutyCycleDataJNI.java
index 3228341..8f244ca 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/DutyCycleDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/DutyCycleDataJNI.java
@@ -1,28 +1,37 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class DutyCycleDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
-  public static native int registerFrequencyCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerFrequencyCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelFrequencyCallback(int index, int uid);
+
   public static native int getFrequency(int index);
+
   public static native void setFrequency(int index, int frequency);
 
-  public static native int registerOutputCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerOutputCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelOutputCallback(int index, int uid);
+
   public static native double getOutput(int index);
+
   public static native void setOutput(int index, double output);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/EncoderDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/EncoderDataJNI.java
index db78d3c..fc9d2e5 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/EncoderDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/EncoderDataJNI.java
@@ -1,58 +1,90 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class EncoderDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
-  public static native int registerCountCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerCountCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelCountCallback(int index, int uid);
+
   public static native int getCount(int index);
+
   public static native void setCount(int index, int count);
 
-  public static native int registerPeriodCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerPeriodCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelPeriodCallback(int index, int uid);
+
   public static native double getPeriod(int index);
+
   public static native void setPeriod(int index, double period);
 
-  public static native int registerResetCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerResetCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelResetCallback(int index, int uid);
+
   public static native boolean getReset(int index);
+
   public static native void setReset(int index, boolean reset);
 
-  public static native int registerMaxPeriodCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerMaxPeriodCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelMaxPeriodCallback(int index, int uid);
+
   public static native double getMaxPeriod(int index);
+
   public static native void setMaxPeriod(int index, double maxPeriod);
 
-  public static native int registerDirectionCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerDirectionCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelDirectionCallback(int index, int uid);
+
   public static native boolean getDirection(int index);
+
   public static native void setDirection(int index, boolean direction);
 
-  public static native int registerReverseDirectionCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerReverseDirectionCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelReverseDirectionCallback(int index, int uid);
+
   public static native boolean getReverseDirection(int index);
+
   public static native void setReverseDirection(int index, boolean reverseDirection);
 
-  public static native int registerSamplesToAverageCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerSamplesToAverageCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelSamplesToAverageCallback(int index, int uid);
+
   public static native int getSamplesToAverage(int index);
+
   public static native void setSamplesToAverage(int index, int samplesToAverage);
 
   public static native void setDistance(int index, double distance);
+
   public static native double getDistance(int index);
+
   public static native void setRate(int index, double rate);
+
   public static native double getRate(int index);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/I2CDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/I2CDataJNI.java
index 8dbc9e6..ebe15eb 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/I2CDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/I2CDataJNI.java
@@ -1,24 +1,27 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class I2CDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
   public static native int registerReadCallback(int index, BufferCallback callback);
+
   public static native void cancelReadCallback(int index, int uid);
 
   public static native int registerWriteCallback(int index, ConstBufferCallback callback);
+
   public static native void cancelWriteCallback(int index, int uid);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/NotifierDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/NotifierDataJNI.java
index 823318c..9c7b0a2 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/NotifierDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/NotifierDataJNI.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
@@ -11,5 +8,6 @@
 
 public class NotifierDataJNI extends JNIWrapper {
   public static native long getNextTimeout();
+
   public static native int getNumNotifiers();
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/NotifyCallback.java b/hal/src/main/java/edu/wpi/first/hal/simulation/NotifyCallback.java
index 22ec015..55605b8 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/NotifyCallback.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/NotifyCallback.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/PCMDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/PCMDataJNI.java
deleted file mode 100644
index 6b72297..0000000
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/PCMDataJNI.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.hal.simulation;
-
-import edu.wpi.first.hal.JNIWrapper;
-
-public class PCMDataJNI extends JNIWrapper {
-  public static native int registerSolenoidInitializedCallback(int index, int channel, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelSolenoidInitializedCallback(int index, int channel, int uid);
-  public static native boolean getSolenoidInitialized(int index, int channel);
-  public static native void setSolenoidInitialized(int index, int channel, boolean solenoidInitialized);
-
-  public static native int registerSolenoidOutputCallback(int index, int channel, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelSolenoidOutputCallback(int index, int channel, int uid);
-  public static native boolean getSolenoidOutput(int index, int channel);
-  public static native void setSolenoidOutput(int index, int channel, boolean solenoidOutput);
-
-  public static native int registerCompressorInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelCompressorInitializedCallback(int index, int uid);
-  public static native boolean getCompressorInitialized(int index);
-  public static native void setCompressorInitialized(int index, boolean compressorInitialized);
-
-  public static native int registerCompressorOnCallback(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelCompressorOnCallback(int index, int uid);
-  public static native boolean getCompressorOn(int index);
-  public static native void setCompressorOn(int index, boolean compressorOn);
-
-  public static native int registerClosedLoopEnabledCallback(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelClosedLoopEnabledCallback(int index, int uid);
-  public static native boolean getClosedLoopEnabled(int index);
-  public static native void setClosedLoopEnabled(int index, boolean closeLoopEnabled);
-
-  public static native int registerPressureSwitchCallback(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelPressureSwitchCallback(int index, int uid);
-  public static native boolean getPressureSwitch(int index);
-  public static native void setPressureSwitch(int index, boolean pressureSwitch);
-
-  public static native int registerCompressorCurrentCallback(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelCompressorCurrentCallback(int index, int uid);
-  public static native double getCompressorCurrent(int index);
-  public static native void setCompressorCurrent(int index, double compressorCurrent);
-
-  public static native void registerAllNonSolenoidCallbacks(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void registerAllSolenoidCallbacks(int index, int channel, NotifyCallback callback, boolean initialNotify);
-
-  public static native void resetData(int index);
-}
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/PDPDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/PDPDataJNI.java
deleted file mode 100644
index 8825f60..0000000
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/PDPDataJNI.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-package edu.wpi.first.hal.simulation;
-
-import edu.wpi.first.hal.JNIWrapper;
-
-public class PDPDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelInitializedCallback(int index, int uid);
-  public static native boolean getInitialized(int index);
-  public static native void setInitialized(int index, boolean initialized);
-
-  public static native int registerTemperatureCallback(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelTemperatureCallback(int index, int uid);
-  public static native double getTemperature(int index);
-  public static native void setTemperature(int index, double temperature);
-
-  public static native int registerVoltageCallback(int index, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelVoltageCallback(int index, int uid);
-  public static native double getVoltage(int index);
-  public static native void setVoltage(int index, double voltage);
-
-
-  public static native int registerCurrentCallback(int index, int channel, NotifyCallback callback, boolean initialNotify);
-  public static native void cancelCurrentCallback(int index, int channel, int uid);
-  public static native double getCurrent(int index, int channel);
-  public static native void setCurrent(int index, int channel, double current);
-
-  public static native void resetData(int index);
-}
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/PWMDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/PWMDataJNI.java
index f44b56b..bf75398 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/PWMDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/PWMDataJNI.java
@@ -1,43 +1,64 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class PWMDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
-  public static native int registerRawValueCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerRawValueCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelRawValueCallback(int index, int uid);
+
   public static native int getRawValue(int index);
+
   public static native void setRawValue(int index, int rawValue);
 
-  public static native int registerSpeedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerSpeedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelSpeedCallback(int index, int uid);
+
   public static native double getSpeed(int index);
+
   public static native void setSpeed(int index, double speed);
 
-  public static native int registerPositionCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerPositionCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelPositionCallback(int index, int uid);
+
   public static native double getPosition(int index);
+
   public static native void setPosition(int index, double position);
 
-  public static native int registerPeriodScaleCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerPeriodScaleCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelPeriodScaleCallback(int index, int uid);
+
   public static native int getPeriodScale(int index);
+
   public static native void setPeriodScale(int index, int periodScale);
 
-  public static native int registerZeroLatchCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerZeroLatchCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelZeroLatchCallback(int index, int uid);
+
   public static native boolean getZeroLatch(int index);
+
   public static native void setZeroLatch(int index, boolean zeroLatch);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/PowerDistributionDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/PowerDistributionDataJNI.java
new file mode 100644
index 0000000..c17da13
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/PowerDistributionDataJNI.java
@@ -0,0 +1,47 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+package edu.wpi.first.hal.simulation;
+
+import edu.wpi.first.hal.JNIWrapper;
+
+public class PowerDistributionDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelInitializedCallback(int index, int uid);
+
+  public static native boolean getInitialized(int index);
+
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerTemperatureCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelTemperatureCallback(int index, int uid);
+
+  public static native double getTemperature(int index);
+
+  public static native void setTemperature(int index, double temperature);
+
+  public static native int registerVoltageCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelVoltageCallback(int index, int uid);
+
+  public static native double getVoltage(int index);
+
+  public static native void setVoltage(int index, double voltage);
+
+  public static native int registerCurrentCallback(
+      int index, int channel, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelCurrentCallback(int index, int channel, int uid);
+
+  public static native double getCurrent(int index, int channel);
+
+  public static native void setCurrent(int index, int channel, double current);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/REVPHDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/REVPHDataJNI.java
new file mode 100644
index 0000000..b12fdcb
--- /dev/null
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/REVPHDataJNI.java
@@ -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.
+
+package edu.wpi.first.hal.simulation;
+
+import edu.wpi.first.hal.JNIWrapper;
+
+@SuppressWarnings("AbbreviationAsWordInName")
+public class REVPHDataJNI extends JNIWrapper {
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelInitializedCallback(int index, int uid);
+
+  public static native boolean getInitialized(int index);
+
+  public static native void setInitialized(int index, boolean initialized);
+
+  public static native int registerSolenoidOutputCallback(
+      int index, int channel, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelSolenoidOutputCallback(int index, int channel, int uid);
+
+  public static native boolean getSolenoidOutput(int index, int channel);
+
+  public static native void setSolenoidOutput(int index, int channel, boolean solenoidOutput);
+
+  public static native int registerCompressorOnCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelCompressorOnCallback(int index, int uid);
+
+  public static native boolean getCompressorOn(int index);
+
+  public static native void setCompressorOn(int index, boolean compressorOn);
+
+  public static native int registerClosedLoopEnabledCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelClosedLoopEnabledCallback(int index, int uid);
+
+  public static native boolean getClosedLoopEnabled(int index);
+
+  public static native void setClosedLoopEnabled(int index, boolean closeLoopEnabled);
+
+  public static native int registerPressureSwitchCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelPressureSwitchCallback(int index, int uid);
+
+  public static native boolean getPressureSwitch(int index);
+
+  public static native void setPressureSwitch(int index, boolean pressureSwitch);
+
+  public static native int registerCompressorCurrentCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelCompressorCurrentCallback(int index, int uid);
+
+  public static native double getCompressorCurrent(int index);
+
+  public static native void setCompressorCurrent(int index, double compressorCurrent);
+
+  public static native void registerAllNonSolenoidCallbacks(
+      int index, NotifyCallback callback, boolean initialNotify);
+
+  public static native void registerAllSolenoidCallbacks(
+      int index, int channel, NotifyCallback callback, boolean initialNotify);
+
+  public static native void resetData(int index);
+}
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/RelayDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/RelayDataJNI.java
index e7973a3..3b165e2 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/RelayDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/RelayDataJNI.java
@@ -1,33 +1,46 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class RelayDataJNI extends JNIWrapper {
-  public static native int registerInitializedForwardCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedForwardCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedForwardCallback(int index, int uid);
+
   public static native boolean getInitializedForward(int index);
+
   public static native void setInitializedForward(int index, boolean initializedForward);
 
-  public static native int registerInitializedReverseCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedReverseCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedReverseCallback(int index, int uid);
+
   public static native boolean getInitializedReverse(int index);
+
   public static native void setInitializedReverse(int index, boolean initializedReverse);
 
-  public static native int registerForwardCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerForwardCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelForwardCallback(int index, int uid);
+
   public static native boolean getForward(int index);
+
   public static native void setForward(int index, boolean forward);
 
-  public static native int registerReverseCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerReverseCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelReverseCallback(int index, int uid);
+
   public static native boolean getReverse(int index);
+
   public static native void setReverse(int index, boolean reverse);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/RoboRioDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/RoboRioDataJNI.java
index a95abfe..a822ede 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/RoboRioDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/RoboRioDataJNI.java
@@ -1,89 +1,159 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class RoboRioDataJNI extends JNIWrapper {
-  public static native int registerFPGAButtonCallback(NotifyCallback callback, boolean initialNotify);
+  @SuppressWarnings("AbbreviationAsWordInName")
+  public static native int registerFPGAButtonCallback(
+      NotifyCallback callback, boolean initialNotify);
+
+  @SuppressWarnings("AbbreviationAsWordInName")
   public static native void cancelFPGAButtonCallback(int uid);
+
+  @SuppressWarnings("AbbreviationAsWordInName")
   public static native boolean getFPGAButton();
+
+  @SuppressWarnings("AbbreviationAsWordInName")
   public static native void setFPGAButton(boolean fPGAButton);
 
-  public static native int registerVInVoltageCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerVInVoltageCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelVInVoltageCallback(int uid);
+
   public static native double getVInVoltage();
+
   public static native void setVInVoltage(double vInVoltage);
 
-  public static native int registerVInCurrentCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerVInCurrentCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelVInCurrentCallback(int uid);
+
   public static native double getVInCurrent();
+
   public static native void setVInCurrent(double vInCurrent);
 
-  public static native int registerUserVoltage6VCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserVoltage6VCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserVoltage6VCallback(int uid);
+
   public static native double getUserVoltage6V();
+
   public static native void setUserVoltage6V(double userVoltage6V);
 
-  public static native int registerUserCurrent6VCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserCurrent6VCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserCurrent6VCallback(int uid);
+
   public static native double getUserCurrent6V();
+
   public static native void setUserCurrent6V(double userCurrent6V);
 
-  public static native int registerUserActive6VCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserActive6VCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserActive6VCallback(int uid);
+
   public static native boolean getUserActive6V();
+
   public static native void setUserActive6V(boolean userActive6V);
 
-  public static native int registerUserVoltage5VCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserVoltage5VCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserVoltage5VCallback(int uid);
+
   public static native double getUserVoltage5V();
+
   public static native void setUserVoltage5V(double userVoltage5V);
 
-  public static native int registerUserCurrent5VCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserCurrent5VCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserCurrent5VCallback(int uid);
+
   public static native double getUserCurrent5V();
+
   public static native void setUserCurrent5V(double userCurrent5V);
 
-  public static native int registerUserActive5VCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserActive5VCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserActive5VCallback(int uid);
+
   public static native boolean getUserActive5V();
+
   public static native void setUserActive5V(boolean userActive5V);
 
-  public static native int registerUserVoltage3V3Callback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserVoltage3V3Callback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserVoltage3V3Callback(int uid);
+
   public static native double getUserVoltage3V3();
+
   public static native void setUserVoltage3V3(double userVoltage3V3);
 
-  public static native int registerUserCurrent3V3Callback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserCurrent3V3Callback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserCurrent3V3Callback(int uid);
+
   public static native double getUserCurrent3V3();
+
   public static native void setUserCurrent3V3(double userCurrent3V3);
 
-  public static native int registerUserActive3V3Callback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserActive3V3Callback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserActive3V3Callback(int uid);
+
   public static native boolean getUserActive3V3();
+
   public static native void setUserActive3V3(boolean userActive3V3);
 
-  public static native int registerUserFaults6VCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserFaults6VCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserFaults6VCallback(int uid);
+
   public static native int getUserFaults6V();
+
   public static native void setUserFaults6V(int userFaults6V);
 
-  public static native int registerUserFaults5VCallback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserFaults5VCallback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserFaults5VCallback(int uid);
+
   public static native int getUserFaults5V();
+
   public static native void setUserFaults5V(int userFaults5V);
 
-  public static native int registerUserFaults3V3Callback(NotifyCallback callback, boolean initialNotify);
+  public static native int registerUserFaults3V3Callback(
+      NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelUserFaults3V3Callback(int uid);
+
   public static native int getUserFaults3V3();
+
   public static native void setUserFaults3V3(int userFaults3V3);
 
+  public static native int registerBrownoutVoltageCallback(
+      NotifyCallback callback, boolean initialNotify);
+
+  public static native void cancelBrownoutVoltageCallback(int uid);
+
+  public static native double getBrownoutVoltage();
+
+  public static native void setBrownoutVoltage(double brownoutVoltage);
+
   public static native void resetData();
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/SPIAccelerometerDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/SPIAccelerometerDataJNI.java
index 2e8ebae..9ceaad8 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/SPIAccelerometerDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/SPIAccelerometerDataJNI.java
@@ -1,38 +1,55 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class SPIAccelerometerDataJNI extends JNIWrapper {
-  public static native int registerActiveCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerActiveCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelActiveCallback(int index, int uid);
+
   public static native boolean getActive(int index);
+
   public static native void setActive(int index, boolean active);
 
-  public static native int registerRangeCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerRangeCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelRangeCallback(int index, int uid);
+
   public static native int getRange(int index);
+
   public static native void setRange(int index, int range);
 
-  public static native int registerXCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerXCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelXCallback(int index, int uid);
+
   public static native double getX(int index);
+
   public static native void setX(int index, double x);
 
-  public static native int registerYCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerYCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelYCallback(int index, int uid);
+
   public static native double getY(int index);
+
   public static native void setY(int index, double y);
 
-  public static native int registerZCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerZCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelZCallback(int index, int uid);
+
   public static native double getZ(int index);
+
   public static native void setZ(int index, double z);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/SPIDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/SPIDataJNI.java
index fd6b854..11b777e 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/SPIDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/SPIDataJNI.java
@@ -1,27 +1,32 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
 import edu.wpi.first.hal.JNIWrapper;
 
 public class SPIDataJNI extends JNIWrapper {
-  public static native int registerInitializedCallback(int index, NotifyCallback callback, boolean initialNotify);
+  public static native int registerInitializedCallback(
+      int index, NotifyCallback callback, boolean initialNotify);
+
   public static native void cancelInitializedCallback(int index, int uid);
+
   public static native boolean getInitialized(int index);
+
   public static native void setInitialized(int index, boolean initialized);
 
   public static native int registerReadCallback(int index, BufferCallback callback);
+
   public static native void cancelReadCallback(int index, int uid);
 
   public static native int registerWriteCallback(int index, ConstBufferCallback callback);
+
   public static native void cancelWriteCallback(int index, int uid);
 
-  public static native int registerReadAutoReceiveBufferCallback(int index, SpiReadAutoReceiveBufferCallback callback);
+  public static native int registerReadAutoReceiveBufferCallback(
+      int index, SpiReadAutoReceiveBufferCallback callback);
+
   public static native void cancelReadAutoReceiveBufferCallback(int index, int uid);
 
   public static native void resetData(int index);
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceCallback.java b/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceCallback.java
index 2390bf4..d9390ce 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceCallback.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceCallback.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceDataJNI.java
index ea2a9f6..ef6536a 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceDataJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceDataJNI.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
@@ -12,19 +9,27 @@
 
 public class SimDeviceDataJNI extends JNIWrapper {
   public static native void setSimDeviceEnabled(String prefix, boolean enabled);
+
   public static native boolean isSimDeviceEnabled(String name);
 
-  public static native int registerSimDeviceCreatedCallback(String prefix, SimDeviceCallback callback, boolean initialNotify);
+  public static native int registerSimDeviceCreatedCallback(
+      String prefix, SimDeviceCallback callback, boolean initialNotify);
+
   public static native void cancelSimDeviceCreatedCallback(int uid);
 
-  public static native int registerSimDeviceFreedCallback(String prefix, SimDeviceCallback callback);
+  public static native int registerSimDeviceFreedCallback(
+      String prefix, SimDeviceCallback callback, boolean initialNotify);
+
   public static native void cancelSimDeviceFreedCallback(int uid);
 
   public static native int getSimDeviceHandle(String name);
 
+  public static native String getSimDeviceName(int handle);
+
   public static native int getSimValueDeviceHandle(int handle);
 
   public static class SimDeviceInfo {
+    @SuppressWarnings("JavadocMethod")
     public SimDeviceInfo(String name, int handle) {
       this.name = name;
       this.handle = handle;
@@ -36,21 +41,43 @@
     @SuppressWarnings("MemberName")
     public int handle;
   }
+
   public static native SimDeviceInfo[] enumerateSimDevices(String prefix);
 
-  public static native int registerSimValueCreatedCallback(int device, SimValueCallback callback, boolean initialNotify);
+  public static native int registerSimValueCreatedCallback(
+      int device, SimValueCallback callback, boolean initialNotify);
+
   public static native void cancelSimValueCreatedCallback(int uid);
 
-  public static native int registerSimValueChangedCallback(int handle, SimValueCallback callback, boolean initialNotify);
+  public static native int registerSimValueChangedCallback(
+      int handle, SimValueCallback callback, boolean initialNotify);
+
   public static native void cancelSimValueChangedCallback(int uid);
 
+  /**
+   * Register a callback for SimDeviceJNI.resetSimValue(). The callback is called with the old
+   * value.
+   *
+   * @param handle simulated value handle
+   * @param callback callback
+   * @param initialNotify ignored (present for consistency)
+   * @return TODO
+   */
+  public static native int registerSimValueResetCallback(
+      int handle, SimValueCallback callback, boolean initialNotify);
+
+  public static native void cancelSimValueResetCallback(int uid);
+
   public static native int getSimValueHandle(int device, String name);
 
   public static class SimValueInfo {
-    public SimValueInfo(String name, int handle, boolean readonly, int type, long value1, double value2) {
+    @SuppressWarnings("JavadocMethod")
+    public SimValueInfo(
+        String name, int handle, int direction, int type, long value1, double value2) {
       this.name = name;
       this.handle = handle;
-      this.readonly = readonly;
+      this.readonly = direction == 1;
+      this.direction = direction;
       this.value = HALValue.fromNative(type, value1, value2);
     }
 
@@ -61,14 +88,21 @@
     public int handle;
 
     @SuppressWarnings("MemberName")
+    @Deprecated
     public boolean readonly;
 
     @SuppressWarnings("MemberName")
+    public int direction;
+
+    @SuppressWarnings("MemberName")
     public HALValue value;
   }
+
   public static native SimValueInfo[] enumerateSimValues(int device);
 
   public static native String[] getSimValueEnumOptions(int handle);
 
+  public static native double[] getSimValueEnumDoubleValues(int handle);
+
   public static native void resetSimDeviceData();
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/SimValueCallback.java b/hal/src/main/java/edu/wpi/first/hal/simulation/SimValueCallback.java
index d65ab38..4f9da94 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/SimValueCallback.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/SimValueCallback.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
@@ -11,9 +8,10 @@
 
 @FunctionalInterface
 public interface SimValueCallback {
-  void callback(String name, int handle, boolean readonly, HALValue value);
+  void callback(String name, int handle, int direction, HALValue value);
 
-  default void callbackNative(String name, int handle, boolean readonly, int type, long value1, double value2) {
-    callback(name, handle, readonly, HALValue.fromNative(type, value1, value2));
+  default void callbackNative(
+      String name, int handle, int direction, int type, long value1, double value2) {
+    callback(name, handle, direction, HALValue.fromNative(type, value1, value2));
   }
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/SimulatorJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/SimulatorJNI.java
index 8147507..3dfeb06 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/SimulatorJNI.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/SimulatorJNI.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
@@ -11,14 +8,24 @@
 
 public class SimulatorJNI extends JNIWrapper {
   public static native void setRuntimeType(int type);
+
   public static native void waitForProgramStart();
+
   public static native void setProgramStarted();
+
   public static native boolean getProgramStarted();
+
   public static native void restartTiming();
+
   public static native void pauseTiming();
+
   public static native void resumeTiming();
+
   public static native boolean isTimingPaused();
+
   public static native void stepTiming(long delta);
+
   public static native void stepTimingAsync(long delta);
+
   public static native void resetHandles();
 }
diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/SpiReadAutoReceiveBufferCallback.java b/hal/src/main/java/edu/wpi/first/hal/simulation/SpiReadAutoReceiveBufferCallback.java
index 8061b5b..10dd0d2 100644
--- a/hal/src/main/java/edu/wpi/first/hal/simulation/SpiReadAutoReceiveBufferCallback.java
+++ b/hal/src/main/java/edu/wpi/first/hal/simulation/SpiReadAutoReceiveBufferCallback.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.simulation;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/AllocationException.java b/hal/src/main/java/edu/wpi/first/hal/util/AllocationException.java
index 42e2059..e9f9a91 100644
--- a/hal/src/main/java/edu/wpi/first/hal/util/AllocationException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/util/AllocationException.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.util;
 
-/**
- * Exception indicating that the resource is already allocated.
- */
+/** Exception indicating that the resource is already allocated. */
 @SuppressWarnings("serial")
 public class AllocationException extends RuntimeException {
   /**
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/BoundaryException.java b/hal/src/main/java/edu/wpi/first/hal/util/BoundaryException.java
index 8fef4c9..683980d 100644
--- a/hal/src/main/java/edu/wpi/first/hal/util/BoundaryException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/util/BoundaryException.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.util;
 
@@ -31,8 +28,8 @@
    */
   public static void assertWithinBounds(double value, double lower, double upper) {
     if (value < lower || value > upper) {
-      throw new BoundaryException("Value must be between " + lower + " and " + upper + ", " + value
-          + " given");
+      throw new BoundaryException(
+          "Value must be between " + lower + " and " + upper + ", " + value + " given");
     }
   }
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/CheckedAllocationException.java b/hal/src/main/java/edu/wpi/first/hal/util/CheckedAllocationException.java
index d9a8a80..6155f17 100644
--- a/hal/src/main/java/edu/wpi/first/hal/util/CheckedAllocationException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/util/CheckedAllocationException.java
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.util;
 
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/HalHandleException.java b/hal/src/main/java/edu/wpi/first/hal/util/HalHandleException.java
index a775ec4..65c11f5 100644
--- a/hal/src/main/java/edu/wpi/first/hal/util/HalHandleException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/util/HalHandleException.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.util;
 
-/**
- * Exception indicating that an error has occurred with a HAL Handle.
- */
+/** Exception indicating that an error has occurred with a HAL Handle. */
 @SuppressWarnings("serial")
 public class HalHandleException extends RuntimeException {
   /**
diff --git a/hal/src/main/java/edu/wpi/first/hal/util/UncleanStatusException.java b/hal/src/main/java/edu/wpi/first/hal/util/UncleanStatusException.java
index 3d6ab36..90650fc 100644
--- a/hal/src/main/java/edu/wpi/first/hal/util/UncleanStatusException.java
+++ b/hal/src/main/java/edu/wpi/first/hal/util/UncleanStatusException.java
@@ -1,15 +1,10 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.hal.util;
 
-/**
- * Exception for bad status codes from the chip object.
- */
+/** Exception for bad status codes from the chip object. */
 @SuppressWarnings("serial")
 public final class UncleanStatusException extends IllegalStateException {
   private final int m_statusCode;
@@ -17,7 +12,7 @@
   /**
    * Create a new UncleanStatusException.
    *
-   * @param status  the status code that caused the exception
+   * @param status the status code that caused the exception
    * @param message A message describing the exception
    */
   public UncleanStatusException(int status, String message) {
@@ -43,9 +38,7 @@
     this(-1, message);
   }
 
-  /**
-   * Create a new UncleanStatusException.
-   */
+  /** Create a new UncleanStatusException. */
   public UncleanStatusException() {
     this(-1, "Status code was non-zero");
   }
diff --git a/hal/src/main/native/athena/Accelerometer.cpp b/hal/src/main/native/athena/Accelerometer.cpp
index bc4d502..73b1357 100644
--- a/hal/src/main/native/athena/Accelerometer.cpp
+++ b/hal/src/main/native/athena/Accelerometer.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/Accelerometer.h"
 
@@ -78,11 +75,9 @@
   kReg_OffZ = 0x31
 };
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAccelerometer() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 namespace hal {
 
@@ -94,7 +89,7 @@
  */
 static void initializeAccelerometer() {
   hal::init::CheckInit();
-  int32_t status;
+  int32_t status = 0;
 
   if (!accel) {
     accel.reset(tAccel::create(&status));
@@ -126,7 +121,8 @@
   // Execute and wait until it's done (up to a millisecond)
   initialTime = HAL_GetFPGATime(&status);
   while (accel->readSTAT(&status) & 1) {
-    if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
+    if (HAL_GetFPGATime(&status) > initialTime + 1000)
+      break;
   }
 
   // Send a stop transmit/receive message with the data
@@ -137,7 +133,8 @@
   // Execute and wait until it's done (up to a millisecond)
   initialTime = HAL_GetFPGATime(&status);
   while (accel->readSTAT(&status) & 1) {
-    if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
+    if (HAL_GetFPGATime(&status) > initialTime + 1000)
+      break;
   }
 }
 
@@ -154,7 +151,8 @@
   // Execute and wait until it's done (up to a millisecond)
   initialTime = HAL_GetFPGATime(&status);
   while (accel->readSTAT(&status) & 1) {
-    if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
+    if (HAL_GetFPGATime(&status) > initialTime + 1000)
+      break;
   }
 
   // Receive a message with the data and stop
@@ -165,7 +163,8 @@
   // Execute and wait until it's done (up to a millisecond)
   initialTime = HAL_GetFPGATime(&status);
   while (accel->readSTAT(&status) & 1) {
-    if (HAL_GetFPGATime(&status) > initialTime + 1000) break;
+    if (HAL_GetFPGATime(&status) > initialTime + 1000)
+      break;
   }
 
   return accel->readDATI(&status);
diff --git a/hal/src/main/native/athena/AddressableLED.cpp b/hal/src/main/native/athena/AddressableLED.cpp
index 7334c99..74a323a 100644
--- a/hal/src/main/native/athena/AddressableLED.cpp
+++ b/hal/src/main/native/athena/AddressableLED.cpp
@@ -1,19 +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 "hal/AddressableLED.h"
 
 #include <cstring>
 
 #include <FRC_FPGA_ChipObject/fpgainterfacecapi/NiFpga_HMB.h>
+#include <fmt/format.h>
 
 #include "ConstantsInternal.h"
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/AddressableLEDTypes.h"
 #include "hal/ChipObject.h"
@@ -35,8 +34,7 @@
     HAL_AddressableLEDHandle, AddressableLED, kNumAddressableLEDs,
     HAL_HandleEnum::AddressableLED>* addressableLEDHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAddressableLED() {
   static LimitedHandleResource<HAL_AddressableLEDHandle, AddressableLED,
                                kNumAddressableLEDs,
@@ -44,8 +42,7 @@
       alH;
   addressableLEDHandles = &alH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -147,8 +144,13 @@
     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;
   }
 
@@ -178,8 +180,13 @@
     return;
   }
 
-  if (length > led->stringLength) {
+  if (length > led->stringLength || length < 0) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format(
+            "Data length must be less than or equal to {}. {} was requested",
+            led->stringLength, length));
     return;
   }
 
diff --git a/hal/src/main/native/athena/AnalogAccumulator.cpp b/hal/src/main/native/athena/AnalogAccumulator.cpp
index 6664c52..7ff7d47 100644
--- a/hal/src/main/native/athena/AnalogAccumulator.cpp
+++ b/hal/src/main/native/athena/AnalogAccumulator.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/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" {
 
@@ -28,7 +23,8 @@
     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/athena/AnalogGyro.cpp b/hal/src/main/native/athena/AnalogGyro.cpp
index 12d688d..19f26dd 100644
--- a/hal/src/main/native/athena/AnalogGyro.cpp
+++ b/hal/src/main/native/athena/AnalogGyro.cpp
@@ -1,18 +1,17 @@
-/*----------------------------------------------------------------------------*/
-/* 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/AnalogGyro.h"
 
+#include <string>
 #include <thread>
 
-#include <wpi/raw_ostream.h>
+#include <fmt/format.h>
 
 #include "AnalogInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "hal/AnalogAccumulator.h"
 #include "hal/AnalogInput.h"
 #include "hal/handles/IndexedHandleResource.h"
@@ -24,6 +23,7 @@
   double voltsPerDegreePerSecond;
   double offset;
   int32_t center;
+  std::string previousAllocation;
 };
 
 }  // namespace
@@ -39,54 +39,62 @@
 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>
       agHandles;
   analogGyroHandles = &agHandles;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 static void Wait(double seconds) {
-  if (seconds < 0.0) return;
+  if (seconds < 0.0) {
+    return;
+  }
   std::this_thread::sleep_for(std::chrono::duration<double>(seconds));
 }
 
 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;
   gyro->voltsPerDegreePerSecond = 0;
   gyro->offset = 0;
   gyro->center = 0;
 
+  gyro->previousAllocation = allocationLocation ? allocationLocation : "";
+
   return handle;
 }
 
@@ -100,17 +108,25 @@
   gyro->voltsPerDegreePerSecond = kDefaultVoltsPerDegreePerSecond;
 
   HAL_SetAnalogAverageBits(gyro->handle, kAverageBits, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   HAL_SetAnalogOversampleBits(gyro->handle, kOversampleBits, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   double sampleRate =
       kSamplesPerSecond * (1 << (kAverageBits + kOversampleBits));
   HAL_SetAnalogSampleRate(sampleRate, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   Wait(0.1);
 
   HAL_SetAnalogGyroDeadband(handle, 0.0, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
 }
 
 void HAL_FreeAnalogGyro(HAL_GyroHandle handle) {
@@ -151,14 +167,18 @@
     return;
   }
   HAL_ResetAccumulator(gyro->handle, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
 
   const double sampleTime = 1.0 / HAL_GetAnalogSampleRate(status);
   const double overSamples =
       1 << HAL_GetAnalogOversampleBits(gyro->handle, status);
   const double averageSamples =
       1 << HAL_GetAnalogAverageBits(gyro->handle, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   Wait(sampleTime * overSamples * averageSamples);
 }
 
@@ -170,15 +190,19 @@
   }
 
   HAL_InitAccumulator(gyro->handle, status);
-  if (*status != 0) return;
-  wpi::outs() << "Calibrating analog gyro for " << kCalibrationSampleTime
-              << " seconds." << '\n';
+  if (*status != 0) {
+    return;
+  }
+  fmt::print("Calibrating analog gyro for {} seconds.\n",
+             kCalibrationSampleTime);
   Wait(kCalibrationSampleTime);
 
   int64_t value;
   int64_t count;
   HAL_GetAccumulatorOutput(gyro->handle, &value, &count, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
 
   gyro->center = static_cast<int32_t>(
       static_cast<double>(value) / static_cast<double>(count) + 0.5);
@@ -186,7 +210,9 @@
   gyro->offset = static_cast<double>(value) / static_cast<double>(count) -
                  static_cast<double>(gyro->center);
   HAL_SetAccumulatorCenter(gyro->handle, gyro->center, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   HAL_ResetAnalogGyro(handle, status);
 }
 
@@ -200,7 +226,9 @@
   int32_t deadband = static_cast<int32_t>(
       volts * 1e9 / HAL_GetAnalogLSBWeight(gyro->handle, status) *
       (1 << HAL_GetAnalogOversampleBits(gyro->handle, status)));
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   HAL_SetAccumulatorDeadband(gyro->handle, deadband, status);
 }
 
diff --git a/hal/src/main/native/athena/AnalogInput.cpp b/hal/src/main/native/athena/AnalogInput.cpp
index 1d502b9..6b3add1 100644
--- a/hal/src/main/native/athena/AnalogInput.cpp
+++ b/hal/src/main/native/athena/AnalogInput.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/AnalogInput.h"
 
@@ -12,44 +9,52 @@
 
 #include "AnalogInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/AnalogAccumulator.h"
 #include "hal/handles/HandlesInternal.h"
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogInput() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 using namespace hal;
 
 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();
   initializeAnalog(status);
 
-  if (*status != 0) return HAL_kInvalidHandle;
+  if (*status != 0) {
+    return HAL_kInvalidHandle;
+  }
 
   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);
   if (HAL_IsAccumulatorChannel(handle, status)) {
     analog_port->accumulator.reset(tAccumulator::create(channel, status));
@@ -61,6 +66,8 @@
   analogInputSystem->writeScanList(channel, channel, status);
   HAL_SetAnalogAverageBits(handle, kDefaultAverageBits, status);
   HAL_SetAnalogOversampleBits(handle, kDefaultOversampleBits, status);
+  analog_port->previousAllocation =
+      allocationLocation ? allocationLocation : "";
   return handle;
 }
 
@@ -69,7 +76,9 @@
   analogInputHandles->Free(analogPortHandle);
 }
 
-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;
@@ -83,13 +92,17 @@
   // TODO: Need double comparison with epsilon.
   // wpi_assert(!sampleRateSet || GetSampleRate() == samplesPerSecond);
   initializeAnalog(status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   setAnalogSampleRate(samplesPerSecond, status);
 }
 
 double HAL_GetAnalogSampleRate(int32_t* status) {
   initializeAnalog(status);
-  if (*status != 0) return 0;
+  if (*status != 0) {
+    return 0;
+  }
   uint32_t ticksPerConversion = analogInputSystem->readLoopTiming(status);
   uint32_t ticksPerSample =
       ticksPerConversion * getAnalogNumActiveChannels(status);
diff --git a/hal/src/main/native/athena/AnalogInternal.cpp b/hal/src/main/native/athena/AnalogInternal.cpp
index 6ac16b8..7ae6adc 100644
--- a/hal/src/main/native/athena/AnalogInternal.cpp
+++ b/hal/src/main/native/athena/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"
 
@@ -43,9 +40,13 @@
 
 void initializeAnalog(int32_t* status) {
   hal::init::CheckInit();
-  if (analogSystemInitialized) return;
+  if (analogSystemInitialized) {
+    return;
+  }
   std::scoped_lock lock(analogRegisterWindowMutex);
-  if (analogSystemInitialized) return;
+  if (analogSystemInitialized) {
+    return;
+  }
   analogInputSystem.reset(tAI::create(status));
   analogOutputSystem.reset(tAO::create(status));
   setAnalogNumChannelsToActivate(kNumAnalogInputs);
@@ -55,7 +56,9 @@
 
 int32_t getAnalogNumActiveChannels(int32_t* status) {
   int32_t scanSize = analogInputSystem->readConfig_ScanSize(status);
-  if (scanSize == 0) return 8;
+  if (scanSize == 0) {
+    return 8;
+  }
   return scanSize;
 }
 
@@ -64,8 +67,9 @@
 }
 
 int32_t getAnalogNumChannelsToActivate(int32_t* status) {
-  if (analogNumChannelsToActivate == 0)
+  if (analogNumChannelsToActivate == 0) {
     return getAnalogNumActiveChannels(status);
+  }
   return analogNumChannelsToActivate;
 }
 
@@ -82,7 +86,9 @@
       ticksPerSample / getAnalogNumChannelsToActivate(status);
   // ticksPerConversion must be at least 80
   if (ticksPerConversion < 80) {
-    if ((*status) >= 0) *status = SAMPLE_RATE_TOO_HIGH;
+    if ((*status) >= 0) {
+      *status = SAMPLE_RATE_TOO_HIGH;
+    }
     ticksPerConversion = 80;
   }
 
diff --git a/hal/src/main/native/athena/AnalogInternal.h b/hal/src/main/native/athena/AnalogInternal.h
index a74562f..431c624 100644
--- a/hal/src/main/native/athena/AnalogInternal.h
+++ b/hal/src/main/native/athena/AnalogInternal.h
@@ -1,15 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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
 
 #include <stdint.h>
 
 #include <memory>
+#include <string>
 
 #include <wpi/mutex.h>
 
@@ -34,6 +32,7 @@
 struct AnalogPort {
   uint8_t channel;
   std::unique_ptr<tAccumulator> accumulator;
+  std::string previousAllocation;
 };
 
 extern IndexedHandleResource<HAL_AnalogInputHandle, hal::AnalogPort,
diff --git a/hal/src/main/native/athena/AnalogOutput.cpp b/hal/src/main/native/athena/AnalogOutput.cpp
index 77f841b..eab7d82 100644
--- a/hal/src/main/native/athena/AnalogOutput.cpp
+++ b/hal/src/main/native/athena/AnalogOutput.cpp
@@ -1,14 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* 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/AnalogOutput.h"
 
+#include <string>
+
 #include "AnalogInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/Errors.h"
 #include "hal/handles/HandlesInternal.h"
@@ -20,6 +20,7 @@
 
 struct AnalogOutput {
   uint8_t channel;
+  std::string previousAllocation;
 };
 
 }  // namespace
@@ -28,45 +29,53 @@
                              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();
   initializeAnalog(status);
 
-  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;
   }
 
-  HAL_AnalogOutputHandle handle =
-      analogOutputHandles->Allocate(channel, status);
-
-  if (*status != 0)
-    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;
+  int16_t channel = getPortHandleChannel(portHandle);
+  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;
+  auto port = analogOutputHandles->Allocate(channel, &handle, status);
+
+  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.
+  }
+
   port->channel = static_cast<uint8_t>(channel);
+  port->previousAllocation = allocationLocation ? allocationLocation : "";
+
   return handle;
 }
 
@@ -85,10 +94,11 @@
 
   uint16_t rawValue = static_cast<uint16_t>(voltage / 5.0 * 0x1000);
 
-  if (voltage < 0.0)
+  if (voltage < 0.0) {
     rawValue = 0;
-  else if (voltage > 5.0)
+  } else if (voltage > 5.0) {
     rawValue = 0x1000;
+  }
 
   analogOutputSystem->writeMXP(port->channel, rawValue, status);
 }
diff --git a/hal/src/main/native/athena/AnalogTrigger.cpp b/hal/src/main/native/athena/AnalogTrigger.cpp
index 9ec3f29..d9e2b92 100644
--- a/hal/src/main/native/athena/AnalogTrigger.cpp
+++ b/hal/src/main/native/athena/AnalogTrigger.cpp
@@ -1,15 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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/AnalogTrigger.h"
 
 #include "AnalogInternal.h"
 #include "DutyCycleInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/AnalogInput.h"
 #include "hal/DutyCycle.h"
@@ -33,8 +31,7 @@
                              kNumAnalogTriggers, HAL_HandleEnum::AnalogTrigger>*
     analogTriggerHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeAnalogTrigger() {
   static LimitedHandleResource<HAL_AnalogTriggerHandle, AnalogTrigger,
                                kNumAnalogTriggers,
@@ -42,8 +39,7 @@
       atH;
   analogTriggerHandles = &atH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -143,6 +139,11 @@
 
   if (lower < 0.0 || upper > 1.0) {
     *status = PARAMETER_OUT_OF_RANGE;
+    auto lowerStr = std::to_string(lower);
+    auto upperStr = std::to_string(upper);
+    hal::SetLastError(
+        status, "Lower must be >= 0 and upper must be <=1. Requested lower " +
+                    lowerStr + " Requested upper " + upperStr);
     return;
   }
 
diff --git a/hal/src/main/native/athena/CAN.cpp b/hal/src/main/native/athena/CAN.cpp
index 8105358..3436a0b 100644
--- a/hal/src/main/native/athena/CAN.cpp
+++ b/hal/src/main/native/athena/CAN.cpp
@@ -1,19 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* 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/CAN.h"
 
 #include <FRC_NetworkCommunication/CANSessionMux.h>
 
-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/athena/CANAPI.cpp b/hal/src/main/native/athena/CANAPI.cpp
index d460885..a7c5b37 100644
--- a/hal/src/main/native/athena/CANAPI.cpp
+++ b/hal/src/main/native/athena/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"
 
@@ -47,15 +44,13 @@
   return ms & 0xFFFFFFFF;
 }
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeCANAPI() {
   static UnlimitedHandleResource<HAL_CANHandle, CANStorage, HAL_HandleEnum::CAN>
       cH;
   canHandles = &cH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 static int32_t CreateCANId(CANStorage* storage, int32_t apiId) {
   int32_t createdId = 0;
diff --git a/hal/src/main/native/athena/CTREPCM.cpp b/hal/src/main/native/athena/CTREPCM.cpp
new file mode 100644
index 0000000..b000ace
--- /dev/null
+++ b/hal/src/main/native/athena/CTREPCM.cpp
@@ -0,0 +1,399 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <fmt/format.h>
+
+#include "HALInitializer.h"
+#include "HALInternal.h"
+#include "PortsInternal.h"
+#include "hal/CANAPI.h"
+#include "hal/Errors.h"
+#include "hal/handles/IndexedHandleResource.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_kPneumatics;
+
+static constexpr int32_t Status1 = 0x50;
+static constexpr int32_t StatusSolFaults = 0x51;
+static constexpr int32_t StatusDebug = 0x52;
+
+static constexpr int32_t Control1 = 0x70;
+static constexpr int32_t Control2 = 0x71;
+static constexpr int32_t Control3 = 0x72;
+
+static constexpr int32_t TimeoutMs = 100;
+static constexpr int32_t SendPeriod = 20;
+
+union PcmStatus {
+  uint8_t data[8];
+  struct Bits {
+    /* Byte 0 */
+    unsigned SolenoidBits : 8;
+    /* Byte 1 */
+    unsigned compressorOn : 1;
+    unsigned stickyFaultFuseTripped : 1;
+    unsigned stickyFaultCompCurrentTooHigh : 1;
+    unsigned faultFuseTripped : 1;
+    unsigned faultCompCurrentTooHigh : 1;
+    unsigned faultHardwareFailure : 1;
+    unsigned isCloseloopEnabled : 1;
+    unsigned pressureSwitchEn : 1;
+    /* Byte 2*/
+    unsigned battVoltage : 8;
+    /* Byte 3 */
+    unsigned solenoidVoltageTop8 : 8;
+    /* Byte 4 */
+    unsigned compressorCurrentTop6 : 6;
+    unsigned solenoidVoltageBtm2 : 2;
+    /* Byte 5 */
+    unsigned StickyFault_dItooHigh : 1;
+    unsigned Fault_dItooHigh : 1;
+    unsigned moduleEnabled : 1;
+    unsigned closedLoopOutput : 1;
+    unsigned compressorCurrentBtm4 : 4;
+    /* Byte 6 */
+    unsigned tokenSeedTop8 : 8;
+    /* Byte 7 */
+    unsigned tokenSeedBtm8 : 8;
+  } bits;
+};
+
+union PcmControl {
+  uint8_t data[8];
+  struct Bits {
+    /* Byte 0 */
+    unsigned tokenTop8 : 8;
+    /* Byte 1 */
+    unsigned tokenBtm8 : 8;
+    /* Byte 2 */
+    unsigned solenoidBits : 8;
+    /* Byte 3*/
+    unsigned reserved : 4;
+    unsigned closeLoopOutput : 1;
+    unsigned compressorOn : 1;
+    unsigned closedLoopEnable : 1;
+    unsigned clearStickyFaults : 1;
+    /* Byte 4 */
+    unsigned OneShotField_h8 : 8;
+    /* Byte 5 */
+    unsigned OneShotField_l8 : 8;
+  } bits;
+};
+
+struct PcmControlSetOneShotDur {
+  uint8_t sol10MsPerUnit[8];
+};
+
+union PcmStatusFault {
+  uint8_t data[8];
+  struct Bits {
+    /* Byte 0 */
+    unsigned SolenoidDisabledList : 8;
+    /* Byte 1 */
+    unsigned reserved_bit0 : 1;
+    unsigned reserved_bit1 : 1;
+    unsigned reserved_bit2 : 1;
+    unsigned reserved_bit3 : 1;
+    unsigned StickyFault_CompNoCurrent : 1;
+    unsigned Fault_CompNoCurrent : 1;
+    unsigned StickyFault_SolenoidJumper : 1;
+    unsigned Fault_SolenoidJumper : 1;
+  } bits;
+};
+
+union PcmDebug {
+  uint8_t data[8];
+  struct Bits {
+    unsigned tokFailsTop8 : 8;
+    unsigned tokFailsBtm8 : 8;
+    unsigned lastFailedTokTop8 : 8;
+    unsigned lastFailedTokBtm8 : 8;
+    unsigned tokSuccessTop8 : 8;
+    unsigned tokSuccessBtm8 : 8;
+  } bits;
+};
+
+namespace {
+struct PCM {
+  HAL_CANHandle canHandle;
+  wpi::mutex lock;
+  std::string previousAllocation;
+  PcmControl control;
+  PcmControlSetOneShotDur oneShot;
+};
+}  // 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
+
+#define READ_PACKET(type, frame, failureValue)                             \
+  auto pcm = pcmHandles->Get(handle);                                      \
+  if (pcm == nullptr) {                                                    \
+    *status = HAL_HANDLE_ERROR;                                            \
+    return failureValue;                                                   \
+  }                                                                        \
+  type pcmStatus;                                                          \
+  int32_t length = 0;                                                      \
+  uint64_t receivedTimestamp = 0;                                          \
+  HAL_ReadCANPacketTimeout(pcm->canHandle, frame, pcmStatus.data, &length, \
+                           &receivedTimestamp, TimeoutMs, status);         \
+  if (*status != 0) {                                                      \
+    return failureValue;                                                   \
+  }
+
+#define READ_STATUS(failureValue) READ_PACKET(PcmStatus, Status1, failureValue)
+#define READ_SOL_FAULTS(failureValue) \
+  READ_PACKET(PcmStatusFault, StatusSolFaults, failureValue)
+
+static void SendControl(PCM* pcm, int32_t* status) {
+  HAL_WriteCANPacketRepeating(pcm->canHandle, pcm->control.data, 8, Control1,
+                              SendPeriod, status);
+}
+
+extern "C" {
+
+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->canHandle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
+  if (*status != 0) {
+    pcmHandles->Free(handle);
+    return HAL_kInvalidHandle;
+  }
+
+  std::memset(&pcm->oneShot, 0, sizeof(pcm->oneShot));
+  std::memset(&pcm->control, 0, sizeof(pcm->control));
+
+  pcm->previousAllocation = allocationLocation ? allocationLocation : "";
+
+  // Enable closed loop control
+  HAL_SetCTREPCMClosedLoopControl(handle, true, status);
+  if (*status != 0) {
+    HAL_FreeCTREPCM(handle);
+    return HAL_kInvalidHandle;
+  }
+  return handle;
+}
+
+void HAL_FreeCTREPCM(HAL_CTREPCMHandle handle) {
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm) {
+    HAL_CleanCAN(pcm->canHandle);
+  }
+  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) {
+  READ_STATUS(false);
+  return pcmStatus.bits.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;
+  }
+
+  std::scoped_lock lock{pcm->lock};
+  pcm->control.bits.closedLoopEnable = enabled ? 1 : 0;
+  SendControl(pcm.get(), status);
+}
+
+HAL_Bool HAL_GetCTREPCMClosedLoopControl(HAL_CTREPCMHandle handle,
+                                         int32_t* status) {
+  READ_STATUS(false);
+  return pcmStatus.bits.isCloseloopEnabled;
+}
+
+HAL_Bool HAL_GetCTREPCMPressureSwitch(HAL_CTREPCMHandle handle,
+                                      int32_t* status) {
+  READ_STATUS(false);
+  return pcmStatus.bits.pressureSwitchEn;
+}
+
+double HAL_GetCTREPCMCompressorCurrent(HAL_CTREPCMHandle handle,
+                                       int32_t* status) {
+  READ_STATUS(0);
+  uint32_t result = pcmStatus.bits.compressorCurrentTop6;
+  result <<= 4;
+  result |= pcmStatus.bits.compressorCurrentBtm4;
+  return result * 0.03125; /* 5.5 fixed pt value in Amps */
+}
+
+HAL_Bool HAL_GetCTREPCMCompressorCurrentTooHighFault(HAL_CTREPCMHandle handle,
+                                                     int32_t* status) {
+  READ_STATUS(false);
+  return pcmStatus.bits.faultCompCurrentTooHigh;
+}
+
+HAL_Bool HAL_GetCTREPCMCompressorCurrentTooHighStickyFault(
+    HAL_CTREPCMHandle handle, int32_t* status) {
+  READ_STATUS(false);
+  return pcmStatus.bits.stickyFaultCompCurrentTooHigh;
+}
+HAL_Bool HAL_GetCTREPCMCompressorShortedStickyFault(HAL_CTREPCMHandle handle,
+                                                    int32_t* status) {
+  READ_STATUS(false);
+  return pcmStatus.bits.Fault_dItooHigh;
+}
+HAL_Bool HAL_GetCTREPCMCompressorShortedFault(HAL_CTREPCMHandle handle,
+                                              int32_t* status) {
+  READ_STATUS(false);
+  return pcmStatus.bits.StickyFault_dItooHigh;
+}
+HAL_Bool HAL_GetCTREPCMCompressorNotConnectedStickyFault(
+    HAL_CTREPCMHandle handle, int32_t* status) {
+  READ_SOL_FAULTS(false);
+  return pcmStatus.bits.StickyFault_CompNoCurrent;
+}
+HAL_Bool HAL_GetCTREPCMCompressorNotConnectedFault(HAL_CTREPCMHandle handle,
+                                                   int32_t* status) {
+  READ_SOL_FAULTS(false);
+  return pcmStatus.bits.Fault_CompNoCurrent;
+}
+
+int32_t HAL_GetCTREPCMSolenoids(HAL_CTREPCMHandle handle, int32_t* status) {
+  READ_STATUS(0);
+  return pcmStatus.bits.SolenoidBits & 0xFF;
+}
+
+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;
+  }
+
+  uint8_t smallMask = mask & 0xFF;
+  uint8_t smallValues =
+      (values & 0xFF) & smallMask;  // Enforce only masked values are set
+  uint8_t invertMask = ~smallMask;
+
+  std::scoped_lock lock{pcm->lock};
+  uint8_t existingValue = invertMask & pcm->control.bits.solenoidBits;
+  pcm->control.bits.solenoidBits = existingValue | smallValues;
+  SendControl(pcm.get(), status);
+}
+
+int32_t HAL_GetCTREPCMSolenoidDisabledList(HAL_CTREPCMHandle handle,
+                                           int32_t* status) {
+  READ_SOL_FAULTS(0);
+  return pcmStatus.bits.SolenoidDisabledList;
+}
+
+HAL_Bool HAL_GetCTREPCMSolenoidVoltageStickyFault(HAL_CTREPCMHandle handle,
+                                                  int32_t* status) {
+  READ_STATUS(false);
+  return pcmStatus.bits.stickyFaultFuseTripped;
+}
+
+HAL_Bool HAL_GetCTREPCMSolenoidVoltageFault(HAL_CTREPCMHandle handle,
+                                            int32_t* status) {
+  READ_STATUS(false);
+  return pcmStatus.bits.faultFuseTripped;
+}
+
+void HAL_ClearAllCTREPCMStickyFaults(HAL_CTREPCMHandle handle,
+                                     int32_t* status) {
+  uint8_t controlData[] = {0, 0, 0, 0x80};
+  HAL_WriteCANPacket(handle, controlData, sizeof(controlData), Control2,
+                     status);
+}
+
+void HAL_FireCTREPCMOneShot(HAL_CTREPCMHandle handle, int32_t index,
+                            int32_t* status) {
+  if (index > 7 || index < 0) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Only [0-7] are valid index values. Requested {}", index));
+    return;
+  }
+
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  std::scoped_lock lock{pcm->lock};
+  uint16_t oneShotField = pcm->control.bits.OneShotField_h8;
+  oneShotField <<= 8;
+  oneShotField |= pcm->control.bits.OneShotField_l8;
+
+  uint16_t shift = 2 * index;
+  uint16_t mask = 3;
+  uint8_t chBits = (oneShotField >> shift) & mask;
+  chBits = (chBits % 3) + 1;
+  oneShotField &= ~(mask << shift);
+  oneShotField |= (chBits << shift);
+  pcm->control.bits.OneShotField_h8 = oneShotField >> 8;
+  pcm->control.bits.OneShotField_l8 = oneShotField;
+  SendControl(pcm.get(), status);
+}
+
+void HAL_SetCTREPCMOneShotDuration(HAL_CTREPCMHandle handle, int32_t index,
+                                   int32_t durMs, int32_t* status) {
+  if (index > 7 || index < 0) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Only [0-7] are valid index values. Requested {}", index));
+    return;
+  }
+
+  auto pcm = pcmHandles->Get(handle);
+  if (pcm == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  std::scoped_lock lock{pcm->lock};
+  pcm->oneShot.sol10MsPerUnit[index] =
+      (std::min)(static_cast<uint32_t>(durMs) / 10,
+                 static_cast<uint32_t>(0xFF));
+  HAL_WriteCANPacketRepeating(pcm->canHandle, pcm->oneShot.sol10MsPerUnit, 8,
+                              Control2, SendPeriod, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/PDP.cpp b/hal/src/main/native/athena/CTREPDP.cpp
similarity index 71%
rename from hal/src/main/native/athena/PDP.cpp
rename to hal/src/main/native/athena/CTREPDP.cpp
index f60e881..1a25a64 100644
--- a/hal/src/main/native/athena/PDP.cpp
+++ b/hal/src/main/native/athena/CTREPDP.cpp
@@ -1,18 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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/PDP.h"
+#include "CTREPDP.h"
 
+#include <fmt/format.h>
 #include <wpi/mutex.h>
 
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/CANAPI.h"
 #include "hal/Errors.h"
+#include "hal/handles/IndexedHandleResource.h"
 
 using namespace hal;
 
@@ -103,72 +103,93 @@
   } bits;
 };
 
-static wpi::mutex pdpHandleMutex;
-static HAL_PDPHandle pdpHandles[kNumPDPModules];
+namespace {
+struct PDP {
+  HAL_CANHandle canHandle;
+  std::string previousAllocation;
+};
+}  // namespace
 
-namespace hal {
-namespace init {
-void InitializePDP() {
-  for (int i = 0; i < kNumPDPModules; i++) {
-    pdpHandles[i] = HAL_kInvalidHandle;
-  }
+static IndexedHandleResource<HAL_PDPHandle, PDP, kNumCTREPDPModules,
+                             HAL_HandleEnum::CTREPDP>* pdpHandles;
+
+namespace hal::init {
+void InitializeCTREPDP() {
+  static IndexedHandleResource<HAL_PDPHandle, PDP, kNumCTREPDPModules,
+                               HAL_HandleEnum::CTREPDP>
+      pH;
+  pdpHandles = &pH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
-HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status) {
+HAL_PDPHandle HAL_InitializePDP(int32_t module, const char* allocationLocation,
+                                int32_t* status) {
   hal::init::CheckInit();
   if (!HAL_CheckPDPModule(module)) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, fmt::format("Invalid pdp module {}", module));
     return HAL_kInvalidHandle;
   }
 
-  std::scoped_lock lock(pdpHandleMutex);
-
-  if (pdpHandles[module] != HAL_kInvalidHandle) {
-    *status = 0;
-    return pdpHandles[module];
-  }
-
-  auto handle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
+  HAL_PDPHandle handle;
+  auto pdp = pdpHandles->Allocate(module, &handle, status);
 
   if (*status != 0) {
-    HAL_CleanCAN(handle);
+    if (pdp) {
+      hal::SetLastErrorPreviouslyAllocated(status, "CTRE PDP", module,
+                                           pdp->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for CTRE PDP", 0,
+                                       kNumCTREPDPModules, module);
+    }
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+  }
+
+  pdp->canHandle = HAL_InitializeCAN(manufacturer, module, deviceType, status);
+  if (*status != 0) {
+    pdpHandles->Free(handle);
     return HAL_kInvalidHandle;
   }
 
-  pdpHandles[module] = handle;
+  pdp->previousAllocation = allocationLocation ? allocationLocation : "";
 
   return handle;
 }
 
 void HAL_CleanPDP(HAL_PDPHandle handle) {
-  HAL_CleanCAN(handle);
-
-  for (int i = 0; i < kNumPDPModules; i++) {
-    if (pdpHandles[i] == handle) {
-      pdpHandles[i] = HAL_kInvalidHandle;
-      return;
-    }
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp) {
+    HAL_CleanCAN(pdp->canHandle);
   }
+  pdpHandles->Free(handle);
+}
+
+int32_t HAL_GetPDPModuleNumber(HAL_PDPHandle handle, int32_t* status) {
+  return hal::getHandleIndex(handle);
 }
 
 HAL_Bool HAL_CheckPDPModule(int32_t module) {
-  return module < kNumPDPModules && module >= 0;
+  return module < kNumCTREPDPModules && module >= 0;
 }
 
 HAL_Bool HAL_CheckPDPChannel(int32_t channel) {
-  return channel < kNumPDPChannels && channel >= 0;
+  return channel < kNumCTREPDPChannels && channel >= 0;
 }
 
 double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
   PdpStatus3 pdpStatus;
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
+  HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, pdpStatus.data, &length,
                            &receivedTimestamp, TimeoutMs, status);
 
   if (*status != 0) {
@@ -179,11 +200,17 @@
 }
 
 double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
   PdpStatus3 pdpStatus;
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
+  HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, pdpStatus.data, &length,
                            &receivedTimestamp, TimeoutMs, status);
 
   if (*status != 0) {
@@ -197,6 +224,13 @@
                                 int32_t* status) {
   if (!HAL_CheckPDPChannel(channel)) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, fmt::format("Invalid pdp channel {}", channel));
+    return 0;
+  }
+
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
     return 0;
   }
 
@@ -207,7 +241,7 @@
 
   if (channel <= 5) {
     PdpStatus1 pdpStatus;
-    HAL_ReadCANPacketTimeout(handle, Status1, pdpStatus.data, &length,
+    HAL_ReadCANPacketTimeout(pdp->canHandle, Status1, pdpStatus.data, &length,
                              &receivedTimestamp, TimeoutMs, status);
     if (*status != 0) {
       return 0;
@@ -240,7 +274,7 @@
     }
   } else if (channel <= 11) {
     PdpStatus2 pdpStatus;
-    HAL_ReadCANPacketTimeout(handle, Status2, pdpStatus.data, &length,
+    HAL_ReadCANPacketTimeout(pdp->canHandle, Status2, pdpStatus.data, &length,
                              &receivedTimestamp, TimeoutMs, status);
     if (*status != 0) {
       return 0;
@@ -273,7 +307,7 @@
     }
   } else {
     PdpStatus3 pdpStatus;
-    HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
+    HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, pdpStatus.data, &length,
                              &receivedTimestamp, TimeoutMs, status);
     if (*status != 0) {
       return 0;
@@ -304,20 +338,32 @@
 
 void HAL_GetPDPAllChannelCurrents(HAL_PDPHandle handle, double* currents,
                                   int32_t* status) {
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
   PdpStatus1 pdpStatus;
-  HAL_ReadCANPacketTimeout(handle, Status1, pdpStatus.data, &length,
+  HAL_ReadCANPacketTimeout(pdp->canHandle, Status1, pdpStatus.data, &length,
                            &receivedTimestamp, TimeoutMs, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   PdpStatus2 pdpStatus2;
-  HAL_ReadCANPacketTimeout(handle, Status2, pdpStatus2.data, &length,
+  HAL_ReadCANPacketTimeout(pdp->canHandle, Status2, pdpStatus2.data, &length,
                            &receivedTimestamp, TimeoutMs, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   PdpStatus3 pdpStatus3;
-  HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus3.data, &length,
+  HAL_ReadCANPacketTimeout(pdp->canHandle, Status3, pdpStatus3.data, &length,
                            &receivedTimestamp, TimeoutMs, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
 
   currents[0] = ((static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
                  pdpStatus.bits.chan1_l2) *
@@ -372,12 +418,18 @@
 }
 
 double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
   PdpStatusEnergy pdpStatus;
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
-                           &receivedTimestamp, TimeoutMs, status);
+  HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, pdpStatus.data,
+                           &length, &receivedTimestamp, TimeoutMs, status);
   if (*status != 0) {
     return 0;
   }
@@ -390,12 +442,18 @@
 }
 
 double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
   PdpStatusEnergy pdpStatus;
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
-                           &receivedTimestamp, TimeoutMs, status);
+  HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, pdpStatus.data,
+                           &length, &receivedTimestamp, TimeoutMs, status);
   if (*status != 0) {
     return 0;
   }
@@ -410,12 +468,18 @@
 }
 
 double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
   PdpStatusEnergy pdpStatus;
   int32_t length = 0;
   uint64_t receivedTimestamp = 0;
 
-  HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
-                           &receivedTimestamp, TimeoutMs, status);
+  HAL_ReadCANPacketTimeout(pdp->canHandle, StatusEnergy, pdpStatus.data,
+                           &length, &receivedTimestamp, TimeoutMs, status);
   if (*status != 0) {
     return 0;
   }
@@ -438,13 +502,25 @@
 }
 
 void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
   uint8_t pdpControl[] = {0x40}; /* only bit set is ResetEnergy */
-  HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
+  HAL_WriteCANPacket(pdp->canHandle, pdpControl, 1, Control1, status);
 }
 
 void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status) {
+  auto pdp = pdpHandles->Get(handle);
+  if (pdp == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
   uint8_t pdpControl[] = {0x80}; /* only bit set is ClearStickyFaults */
-  HAL_WriteCANPacket(handle, pdpControl, 1, Control1, status);
+  HAL_WriteCANPacket(pdp->canHandle, pdpControl, 1, Control1, status);
 }
 
 }  // extern "C"
diff --git a/hal/src/main/native/include/hal/PDP.h b/hal/src/main/native/athena/CTREPDP.h
similarity index 71%
rename from hal/src/main/native/include/hal/PDP.h
rename to hal/src/main/native/athena/CTREPDP.h
index c80e8b6..dd4b298 100644
--- a/hal/src/main/native/include/hal/PDP.h
+++ b/hal/src/main/native/athena/CTREPDP.h
@@ -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.
 
 #pragma once
 
@@ -28,7 +25,8 @@
  * @param  module the module number to initialize
  * @return the created PDP
  */
-HAL_PDPHandle HAL_InitializePDP(int32_t module, int32_t* status);
+HAL_PDPHandle HAL_InitializePDP(int32_t module, const char* allocationLocation,
+                                int32_t* status);
 
 /**
  * Cleans a PDP module.
@@ -38,10 +36,15 @@
 void HAL_CleanPDP(HAL_PDPHandle handle);
 
 /**
+ * Gets the module number for a pdp.
+ */
+int32_t HAL_GetPDPModuleNumber(HAL_PDPHandle handle, int32_t* status);
+
+/**
  * Checks if a PDP channel is valid.
  *
  * @param channel the channel to check
- * @return        true if the channel is valid, otherwise false
+ * @return true if the channel is valid, otherwise false
  */
 HAL_Bool HAL_CheckPDPChannel(int32_t channel);
 
@@ -49,7 +52,7 @@
  * Checks if a PDP module is valid.
  *
  * @param channel the module to check
- * @return        true if the module is valid, otherwise false
+ * @return true if the module is valid, otherwise false
  */
 HAL_Bool HAL_CheckPDPModule(int32_t module);
 
@@ -57,7 +60,7 @@
  * Gets the temperature of the PDP.
  *
  * @param handle the module handle
- * @return       the module temperature (celsius)
+ * @return the module temperature (celsius)
  */
 double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status);
 
@@ -65,7 +68,7 @@
  * Gets the PDP input voltage.
  *
  * @param handle the module handle
- * @return       the input voltage (volts)
+ * @return the input voltage (volts)
  */
 double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status);
 
@@ -74,7 +77,7 @@
  *
  * @param module  the module
  * @param channel the channel
- * @return        the channel current (amps)
+ * @return the channel current (amps)
  */
 double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
                                 int32_t* status);
@@ -94,7 +97,7 @@
  * Gets the total current of the PDP.
  *
  * @param handle the module handle
- * @return       the total current (amps)
+ * @return the total current (amps)
  */
 double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status);
 
@@ -102,7 +105,7 @@
  * Gets the total power of the PDP.
  *
  * @param handle the module handle
- * @return       the total power (watts)
+ * @return the total power (watts)
  */
 double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status);
 
@@ -110,7 +113,7 @@
  * Gets the total energy of the PDP.
  *
  * @param handle the module handle
- * @return       the total energy (joules)
+ * @return the total energy (joules)
  */
 double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status);
 
diff --git a/hal/src/main/native/athena/Compressor.cpp b/hal/src/main/native/athena/Compressor.cpp
deleted file mode 100644
index f381305..0000000
--- a/hal/src/main/native/athena/Compressor.cpp
+++ /dev/null
@@ -1,202 +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 "PCMInternal.h"
-#include "PortsInternal.h"
-#include "ctre/PCM.h"
-#include "hal/Errors.h"
-#include "hal/handles/HandlesInternal.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();
-  // Use status to check for invalid index
-  initializePCM(module, status);
-  if (*status != 0) {
-    return HAL_kInvalidHandle;
-  }
-
-  // As compressors can have unlimited objects, just create a
-  // handle with the module number as the index.
-
-  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;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetCompressor(value);
-
-  return value;
-}
-
-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;
-  }
-
-  *status = PCM_modules[index]->SetClosedLoopControl(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;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetClosedLoopControl(value);
-
-  return value;
-}
-
-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;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetPressure(value);
-
-  return value;
-}
-
-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;
-  }
-  float value;
-
-  *status = PCM_modules[index]->GetCompressorCurrent(value);
-
-  return value;
-}
-HAL_Bool HAL_GetCompressorCurrentTooHighFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetCompressorCurrentTooHighFault(value);
-
-  return value;
-}
-HAL_Bool HAL_GetCompressorCurrentTooHighStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetCompressorCurrentTooHighStickyFault(value);
-
-  return value;
-}
-HAL_Bool HAL_GetCompressorShortedStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetCompressorShortedStickyFault(value);
-
-  return value;
-}
-HAL_Bool HAL_GetCompressorShortedFault(HAL_CompressorHandle compressorHandle,
-                                       int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetCompressorShortedFault(value);
-
-  return value;
-}
-HAL_Bool HAL_GetCompressorNotConnectedStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetCompressorNotConnectedStickyFault(value);
-
-  return value;
-}
-HAL_Bool HAL_GetCompressorNotConnectedFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status) {
-  int16_t index =
-      getHandleTypedIndex(compressorHandle, HAL_HandleEnum::Compressor, 0);
-  if (index == InvalidHandleIndex) {
-    *status = HAL_HANDLE_ERROR;
-    return false;
-  }
-  bool value;
-
-  *status = PCM_modules[index]->GetCompressorNotConnectedFault(value);
-
-  return value;
-}
-
-}  // extern "C"
diff --git a/hal/src/main/native/athena/Constants.cpp b/hal/src/main/native/athena/Constants.cpp
index 6af443d..a312935 100644
--- a/hal/src/main/native/athena/Constants.cpp
+++ b/hal/src/main/native/athena/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" {
 
diff --git a/hal/src/main/native/athena/ConstantsInternal.h b/hal/src/main/native/athena/ConstantsInternal.h
index 55bbdee..21fece4 100644
--- a/hal/src/main/native/athena/ConstantsInternal.h
+++ b/hal/src/main/native/athena/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/athena/Counter.cpp b/hal/src/main/native/athena/Counter.cpp
index 6d7e254..7f84df8 100644
--- a/hal/src/main/native/athena/Counter.cpp
+++ b/hal/src/main/native/athena/Counter.cpp
@@ -1,15 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* 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/Counter.h"
 
+#include <fmt/format.h>
+
 #include "ConstantsInternal.h"
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/HAL.h"
 #include "hal/handles/LimitedHandleResource.h"
@@ -28,16 +28,14 @@
 static LimitedHandleResource<HAL_CounterHandle, Counter, kNumCounters,
                              HAL_HandleEnum::Counter>* counterHandles;
 
-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" {
 
@@ -151,6 +149,9 @@
     // TODO: wpi_setWPIErrorWithContext(ParameterOutOfRange, "Counter only
     // supports DownSource in TwoPulse and ExternalDirection modes.");
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status,
+                      "Counter only supports DownSource in TwoPulse and "
+                      "ExternalDirection mode.");
     return;
   }
 
@@ -265,6 +266,10 @@
   }
   if (samplesToAverage < 1 || samplesToAverage > 127) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, fmt::format("Samples to average must be between "
+                                          "1 and 127 inclusive. Requested {}",
+                                          samplesToAverage));
+    return;
   }
   counter->counter->writeTimerConfig_AverageSize(samplesToAverage, status);
 }
@@ -362,10 +367,11 @@
   }
   if (counter->counter->readConfig_Mode(status) ==
       HAL_Counter_kExternalDirection) {
-    if (reverseDirection)
+    if (reverseDirection) {
       HAL_SetCounterDownSourceEdge(counterHandle, true, true, status);
-    else
+    } else {
       HAL_SetCounterDownSourceEdge(counterHandle, false, true, status);
+    }
   }
 }
 
diff --git a/hal/src/main/native/athena/DIO.cpp b/hal/src/main/native/athena/DIO.cpp
index dc4631e..7b26dd1 100644
--- a/hal/src/main/native/athena/DIO.cpp
+++ b/hal/src/main/native/athena/DIO.cpp
@@ -1,19 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* 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/DIO.h"
 
 #include <cmath>
+#include <cstdio>
 #include <thread>
 
-#include <wpi/raw_ostream.h>
-
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/cpp/fpga_clock.h"
 #include "hal/handles/HandlesInternal.h"
@@ -28,8 +25,7 @@
                              kNumDigitalPWMOutputs, HAL_HandleEnum::DigitalPWM>*
     digitalPWMHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDIO() {
   static LimitedHandleResource<HAL_DigitalPWMHandle, uint8_t,
                                kNumDigitalPWMOutputs,
@@ -37,36 +33,45 @@
       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();
   initializeDigital(status);
 
-  if (*status != 0) return HAL_kInvalidHandle;
-
-  int16_t channel = getPortHandleChannel(portHandle);
-  if (channel == InvalidHandleIndex || channel >= kNumDigitalChannels) {
-    *status = PARAMETER_OUT_OF_RANGE;
+  if (*status != 0) {
     return HAL_kInvalidHandle;
   }
 
-  auto handle =
-      digitalChannelHandles->Allocate(channel, HAL_HandleEnum::DIO, status);
-
-  if (*status != 0)
-    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;
+  int16_t channel = getPortHandleChannel(portHandle);
+  if (channel == InvalidHandleIndex || channel >= kNumDigitalChannels) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for DIO", 0,
+                                     kNumDigitalChannels, channel);
     return HAL_kInvalidHandle;
   }
 
+  HAL_DigitalHandle handle;
+
+  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.
+  }
+
   port->channel = static_cast<uint8_t>(channel);
 
   std::scoped_lock lock(digitalDIOMutex);
@@ -116,6 +121,7 @@
   }
 
   digitalSystem->writeOutputEnable(outputEnable, status);
+  port->previousAllocation = allocationLocation ? allocationLocation : "";
 
   return handle;
 }
@@ -127,7 +133,8 @@
 void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
   auto port = digitalChannelHandles->Get(dioPortHandle, HAL_HandleEnum::DIO);
   // no status, so no need to check for a proper free.
-  if (port == nullptr) return;
+  if (port == nullptr)
+    return;
   digitalChannelHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
 
   // Wait for no other object to hold this handle.
@@ -135,8 +142,8 @@
   while (port.use_count() != 1) {
     auto current = hal::fpga_clock::now();
     if (start + std::chrono::seconds(1) < current) {
-      wpi::outs() << "DIO handle free timeout\n";
-      wpi::outs().flush();
+      std::puts("DIO handle free timeout");
+      std::fflush(stdout);
       break;
     }
     std::this_thread::yield();
@@ -189,9 +196,11 @@
   // higher freq.
   // TODO: Round in the linear rate domain.
   initializeDigital(status);
-  if (*status != 0) return;
-  uint16_t pwmPeriodPower = static_cast<uint16_t>(
-      std::log(1.0 / (16 * 1.0E-6 * rate)) / std::log(2.0) + 0.5);
+  if (*status != 0) {
+    return;
+  }
+  uint16_t pwmPeriodPower =
+      std::lround(std::log(1.0 / (16 * 1.0E-6 * rate)) / std::log(2.0));
   digitalSystem->writePWMPeriodPower(pwmPeriodPower, status);
 }
 
@@ -203,10 +212,16 @@
     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;
+  }
   double rawDutyCycle = 256.0 * dutyCycle;
-  if (rawDutyCycle > 255.5) rawDutyCycle = 255.5;
+  if (rawDutyCycle > 255.5) {
+    rawDutyCycle = 255.5;
+  }
   {
     std::scoped_lock lock(digitalPwmMutex);
     uint16_t pwmPeriodPower = digitalSystem->readPWMPeriodPower(status);
@@ -251,10 +266,35 @@
     return;
   }
   if (value != 0 && value != 1) {
-    if (value != 0) value = 1;
+    if (value != 0) {
+      value = 1;
+    }
   }
   {
     std::scoped_lock lock(digitalDIOMutex);
+
+    tDIO::tOutputEnable currentOutputEnable =
+        digitalSystem->readOutputEnable(status);
+
+    HAL_Bool isInput = false;
+
+    if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
+      isInput =
+          ((currentOutputEnable.SPIPort >> remapSPIChannel(port->channel)) &
+           1) == 0;
+    } else if (port->channel < kNumDigitalHeaders) {
+      isInput = ((currentOutputEnable.Headers >> port->channel) & 1) == 0;
+    } else {
+      isInput = ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) &
+                 1) == 0;
+    }
+
+    if (isInput) {
+      *status = PARAMETER_OUT_OF_RANGE;
+      hal::SetLastError(status, "Cannot set output of an input channel");
+      return;
+    }
+
     tDIO::tDO currentDIO = digitalSystem->readDO(status);
 
     if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
@@ -358,11 +398,11 @@
 
   if (port->channel >= kNumDigitalHeaders + kNumDigitalMXPChannels) {
     return ((currentOutputEnable.SPIPort >> remapSPIChannel(port->channel)) &
-            1) != 0;
+            1) == 0;
   } else if (port->channel < kNumDigitalHeaders) {
-    return ((currentOutputEnable.Headers >> port->channel) & 1) != 0;
+    return ((currentOutputEnable.Headers >> port->channel) & 1) == 0;
   } else {
-    return ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) & 1) !=
+    return ((currentOutputEnable.MXP >> remapMXPChannel(port->channel)) & 1) ==
            0;
   }
 }
@@ -410,7 +450,9 @@
 
 HAL_Bool HAL_IsAnyPulsing(int32_t* status) {
   initializeDigital(status);
-  if (*status != 0) return false;
+  if (*status != 0) {
+    return false;
+  }
   tDIO::tPulse pulseRegister = digitalSystem->readPulse(status);
   return pulseRegister.Headers != 0 && pulseRegister.MXP != 0 &&
          pulseRegister.SPIPort != 0;
@@ -459,7 +501,9 @@
 
 void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status) {
   initializeDigital(status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   std::scoped_lock lock(digitalDIOMutex);
   digitalSystem->writeFilterPeriodHdr(filterIndex, value, status);
   if (*status == 0) {
@@ -469,7 +513,9 @@
 
 int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status) {
   initializeDigital(status);
-  if (*status != 0) return 0;
+  if (*status != 0) {
+    return 0;
+  }
   uint32_t hdrPeriod = 0;
   uint32_t mxpPeriod = 0;
   {
diff --git a/hal/src/main/native/athena/DMA.cpp b/hal/src/main/native/athena/DMA.cpp
index ee39d2d..f7d8b08 100644
--- a/hal/src/main/native/athena/DMA.cpp
+++ b/hal/src/main/native/athena/DMA.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/DMA.h"
 
@@ -14,8 +11,10 @@
 #include <type_traits>
 
 #include "AnalogInternal.h"
+#include "ConstantsInternal.h"
 #include "DigitalInternal.h"
 #include "EncoderInternal.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/AnalogAccumulator.h"
 #include "hal/AnalogGyro.h"
@@ -73,15 +72,13 @@
 static hal::LimitedHandleResource<HAL_DMAHandle, DMA, 1, HAL_HandleEnum::DMA>*
     dmaHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeDMA() {
   static hal::LimitedHandleResource<HAL_DMAHandle, DMA, 1, HAL_HandleEnum::DMA>
       dH;
   dmaHandles = &dH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -107,19 +104,25 @@
     return HAL_kInvalidHandle;
   }
 
-  dma->aDMA->writeConfig_ExternalClock(false, status);
-  if (*status != 0) {
-    dmaHandles->Free(handle);
-    return HAL_kInvalidHandle;
+  std::memset(&dma->captureStore, 0, sizeof(dma->captureStore));
+
+  tDMA::tConfig config;
+  std::memset(&config, 0, sizeof(config));
+  config.Pause = true;
+  dma->aDMA->writeConfig(config, status);
+
+  dma->aDMA->writeRate(1, status);
+
+  tDMA::tExternalTriggers newTrigger;
+  std::memset(&newTrigger, 0, sizeof(newTrigger));
+  for (unsigned char reg = 0; reg < tDMA::kNumExternalTriggersRegisters;
+       reg++) {
+    for (unsigned char bit = 0; bit < tDMA::kNumExternalTriggersElements;
+         bit++) {
+      dma->aDMA->writeExternalTriggers(reg, bit, newTrigger, status);
+    }
   }
 
-  HAL_SetDMARate(handle, 1, status);
-  if (*status != 0) {
-    dmaHandles->Free(handle);
-    return HAL_kInvalidHandle;
-  }
-
-  HAL_SetDMAPause(handle, false, status);
   return handle;
 }
 
@@ -127,7 +130,8 @@
   auto dma = dmaHandles->Get(handle);
   dmaHandles->Free(handle);
 
-  if (!dma) return;
+  if (!dma)
+    return;
 
   int32_t status = 0;
   if (dma->manager) {
@@ -142,20 +146,44 @@
     return;
   }
 
+  if (!dma->manager) {
+    *status = HAL_INVALID_DMA_STATE;
+    return;
+  }
+
   dma->aDMA->writeConfig_Pause(pause, status);
 }
-void HAL_SetDMARate(HAL_DMAHandle handle, int32_t cycles, int32_t* status) {
+
+void HAL_SetDMATimedTrigger(HAL_DMAHandle handle, double seconds,
+                            int32_t* status) {
+  constexpr double baseMultipler = kSystemClockTicksPerMicrosecond * 1000000;
+  uint32_t cycles = static_cast<uint32_t>(baseMultipler * seconds);
+  HAL_SetDMATimedTriggerCycles(handle, cycles, status);
+}
+
+void HAL_SetDMATimedTriggerCycles(HAL_DMAHandle handle, uint32_t cycles,
+                                  int32_t* status) {
   auto dma = dmaHandles->Get(handle);
   if (!dma) {
     *status = HAL_HANDLE_ERROR;
     return;
   }
 
+  if (dma->manager) {
+    *status = HAL_INVALID_DMA_ADDITION;
+    return;
+  }
+
   if (cycles < 1) {
     cycles = 1;
   }
 
-  dma->aDMA->writeRate(static_cast<uint32_t>(cycles), status);
+  dma->aDMA->writeConfig_ExternalClock(false, status);
+  if (*status != 0) {
+    return;
+  }
+
+  dma->aDMA->writeRate(cycles, status);
 }
 
 void HAL_AddDMAEncoder(HAL_DMAHandle handle, HAL_EncoderHandle encoderHandle,
@@ -480,20 +508,20 @@
   }
 }
 
-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) {
   auto dma = dmaHandles->Get(handle);
   if (!dma) {
     *status = HAL_HANDLE_ERROR;
-    return;
+    return 0;
   }
 
   if (dma->manager) {
     *status = HAL_INVALID_DMA_ADDITION;
-    return;
+    return 0;
   }
 
   int index = 0;
@@ -507,19 +535,21 @@
 
   if (index == 8) {
     *status = NO_AVAILABLE_RESOURCES;
-    return;
+    return 0;
   }
 
   dma->captureStore.triggerChannels |= (1 << index);
 
   auto channelIndex = index;
 
-  auto isExternalClock = dma->aDMA->readConfig_ExternalClock(status);
-  if (*status == 0 && !isExternalClock) {
-    dma->aDMA->writeConfig_ExternalClock(true, status);
-    if (*status != 0) return;
-  } else if (*status != 0) {
-    return;
+  dma->aDMA->writeConfig_ExternalClock(true, status);
+  if (*status != 0) {
+    return 0;
+  }
+
+  dma->aDMA->writeRate(1, status);
+  if (*status != 0) {
+    return 0;
   }
 
   uint8_t pin = 0;
@@ -530,7 +560,10 @@
 
   if (!success) {
     *status = PARAMETER_OUT_OF_RANGE;
-    return;
+    hal::SetLastError(status,
+                      "Digital Source unabled to be mapped properly. Likely "
+                      "invalid handle passed.");
+    return 0;
   }
 
   tDMA::tExternalTriggers newTrigger;
@@ -542,6 +575,55 @@
 
   dma->aDMA->writeExternalTriggers(channelIndex / 4, channelIndex % 4,
                                    newTrigger, status);
+  return index;
+}
+
+void HAL_ClearDMASensors(HAL_DMAHandle handle, int32_t* status) {
+  auto dma = dmaHandles->Get(handle);
+  if (!dma) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  if (dma->manager) {
+    *status = HAL_INVALID_DMA_STATE;
+    return;
+  }
+
+  bool existingExternal = dma->aDMA->readConfig_ExternalClock(status);
+  if (*status != 0) {
+    return;
+  }
+
+  tDMA::tConfig config;
+  std::memset(&config, 0, sizeof(config));
+  config.Pause = true;
+  config.ExternalClock = existingExternal;
+  dma->aDMA->writeConfig(config, status);
+}
+
+void HAL_ClearDMAExternalTriggers(HAL_DMAHandle handle, int32_t* status) {
+  auto dma = dmaHandles->Get(handle);
+  if (!dma) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  if (dma->manager) {
+    *status = HAL_INVALID_DMA_STATE;
+    return;
+  }
+
+  dma->captureStore.triggerChannels = 0;
+  tDMA::tExternalTriggers newTrigger;
+  std::memset(&newTrigger, 0, sizeof(newTrigger));
+  for (unsigned char reg = 0; reg < tDMA::kNumExternalTriggersRegisters;
+       reg++) {
+    for (unsigned char bit = 0; bit < tDMA::kNumExternalTriggersElements;
+         bit++) {
+      dma->aDMA->writeExternalTriggers(reg, bit, newTrigger, status);
+    }
+  }
 }
 
 void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status) {
@@ -552,12 +634,14 @@
   }
 
   if (dma->manager) {
-    *status = INCOMPATIBLE_STATE;
+    *status = HAL_INVALID_DMA_STATE;
     return;
   }
 
   tDMA::tConfig config = dma->aDMA->readConfig(status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
 
   {
     size_t accum_size = 0;
@@ -594,12 +678,15 @@
     dma->captureStore.captureSize = accum_size + 1;
   }
 
-  dma->manager = std::make_unique<tDMAManager>(
-      g_DMA_index, queueDepth * dma->captureStore.captureSize, status);
+  uint32_t byteDepth = queueDepth * dma->captureStore.captureSize;
+
+  dma->manager = std::make_unique<tDMAManager>(g_DMA_index, byteDepth, status);
   if (*status != 0) {
     return;
   }
 
+  dma->aDMA->writeConfig_Pause(false, status);
+
   dma->manager->start(status);
   dma->manager->stop(status);
   dma->manager->start(status);
@@ -613,6 +700,8 @@
   }
 
   if (dma->manager) {
+    dma->aDMA->writeConfig_Pause(true, status);
+    *status = 0;
     dma->manager->stop(status);
     dma->manager = nullptr;
   }
@@ -625,7 +714,7 @@
 
 enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
                                          HAL_DMASample* dmaSample,
-                                         int32_t timeoutMs,
+                                         double timeoutSeconds,
                                          int32_t* remainingOut,
                                          int32_t* status) {
   DMA* dma = static_cast<DMA*>(dmaPointer);
@@ -633,12 +722,13 @@
   size_t remainingBytes = 0;
 
   if (!dma->manager) {
-    *status = INCOMPATIBLE_STATE;
+    *status = HAL_INVALID_DMA_STATE;
     return HAL_DMA_ERROR;
   }
 
   dma->manager->read(dmaSample->readBuffer, dma->captureStore.captureSize,
-                     timeoutMs, &remainingBytes, status);
+                     static_cast<uint32_t>(timeoutSeconds * 1000),
+                     &remainingBytes, status);
 
   *remainingOut = remainingBytes / dma->captureStore.captureSize;
 
@@ -663,15 +753,16 @@
 }
 
 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) {
   auto dma = dmaHandles->Get(handle);
   if (!dma) {
     *status = HAL_HANDLE_ERROR;
     return HAL_DMA_ERROR;
   }
 
-  return HAL_ReadDMADirect(dma.get(), dmaSample, timeoutMs, remainingOut,
+  return HAL_ReadDMADirect(dma.get(), dmaSample, timeoutSeconds, remainingOut,
                            status);
 }
 
diff --git a/hal/src/main/native/athena/DigitalInternal.cpp b/hal/src/main/native/athena/DigitalInternal.cpp
index 205ce3e..63ea0aa 100644
--- a/hal/src/main/native/athena/DigitalInternal.cpp
+++ b/hal/src/main/native/athena/DigitalInternal.cpp
@@ -1,13 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "DigitalInternal.h"
 
 #include <atomic>
+#include <cmath>
 #include <thread>
 
 #include <FRC_NetworkCommunication/LoadOut.h>
@@ -46,8 +44,12 @@
 }  // namespace init
 
 namespace detail {
-wpi::mutex& UnsafeGetDIOMutex() { return digitalDIOMutex; }
-tDIO* UnsafeGetDigialSystem() { return digitalSystem.get(); }
+wpi::mutex& UnsafeGetDIOMutex() {
+  return digitalDIOMutex;
+}
+tDIO* UnsafeGetDigialSystem() {
+  return digitalSystem.get();
+}
 int32_t ComputeDigitalMask(HAL_DigitalHandle handle, int32_t* status) {
   auto port = digitalChannelHandles->Get(handle, HAL_HandleEnum::DIO);
   if (port == nullptr) {
@@ -72,11 +74,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;
+  }
 
   digitalSystem.reset(tDIO::create(status));
 
@@ -92,7 +98,8 @@
 
   // Make sure that the 9403 IONode has had a chance to initialize before
   // continuing.
-  while (pwmSystem->readLoopTiming(status) == 0) std::this_thread::yield();
+  while (pwmSystem->readLoopTiming(status) == 0)
+    std::this_thread::yield();
 
   if (pwmSystem->readLoopTiming(status) != kExpectedLoopTiming) {
     *status = LOOP_TIMING_ERROR;  // NOTE: Doesn't display the error
@@ -102,10 +109,10 @@
   double loopTime = pwmSystem->readLoopTiming(status) /
                     (kSystemClockTicksPerMicrosecond * 1e3);
 
-  pwmSystem->writeConfig_Period(
-      static_cast<uint16_t>(kDefaultPwmPeriod / loopTime + 0.5), status);
-  uint16_t minHigh = static_cast<uint16_t>(
-      (kDefaultPwmCenter - kDefaultPwmStepsDown * loopTime) / loopTime + 0.5);
+  pwmSystem->writeConfig_Period(std::lround(kDefaultPwmPeriod / loopTime),
+                                status);
+  uint16_t minHigh = std::lround(
+      (kDefaultPwmCenter - kDefaultPwmStepsDown * loopTime) / loopTime);
   pwmSystem->writeConfig_MinHigh(minHigh, status);
   // Ensure that PWM output values are set to OFF
   for (uint8_t pwmIndex = 0; pwmIndex < kNumPWMChannels; pwmIndex++) {
@@ -158,12 +165,22 @@
     }
     analogTrigger = false;
     return true;
-  } else {
-    return false;
+  } else if (isHandleType(digitalSourceHandle, HAL_HandleEnum::PWM)) {
+    // PWM's on MXP port are supported as a digital source
+    int32_t index = getHandleIndex(digitalSourceHandle);
+    if (index >= kNumPWMHeaders) {
+      channel = remapMXPPWMChannel(index);
+      module = 1;
+      analogTrigger = false;
+      return true;
+    }
   }
+  return false;
 }
 
-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) {
@@ -173,7 +190,9 @@
   }
 }
 
-int32_t remapSPIChannel(int32_t channel) { return channel - 26; }
+int32_t remapSPIChannel(int32_t channel) {
+  return channel - 26;
+}
 
 }  // namespace hal
 
diff --git a/hal/src/main/native/athena/DigitalInternal.h b/hal/src/main/native/athena/DigitalInternal.h
index 2cb9b3c..6b1e909 100644
--- a/hal/src/main/native/athena/DigitalInternal.h
+++ b/hal/src/main/native/athena/DigitalInternal.h
@@ -1,15 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <stdint.h>
 
 #include <memory>
+#include <string>
 
 #include <wpi/mutex.h>
 
@@ -73,6 +71,7 @@
   int32_t centerPwm = 0;
   int32_t deadbandMinPwm = 0;
   int32_t minPwm = 0;
+  std::string previousAllocation;
 };
 
 extern DigitalHandleResource<HAL_DigitalHandle, DigitalPort,
@@ -101,13 +100,15 @@
  */
 constexpr int32_t remapDigitalChannelToBitfieldChannel(int32_t channel) {
   // First 10 are headers
-  if (channel < kNumDigitalHeaders) return channel;
-  // 2nd group of 16 are mxp. So if mxp port, add 6, since they start at 10
-  else if (channel < kNumDigitalMXPChannels)
+  if (channel < kNumDigitalHeaders) {
+    return channel;
+    // 2nd group of 16 are mxp. So if mxp port, add 6, since they start at 10
+  } else if (channel < kNumDigitalMXPChannels) {
     return channel + 6;
-  // Assume SPI, so remove MXP channels
-  else
+    // Assume SPI, so remove MXP channels
+  } else {
     return channel - kNumDigitalMXPChannels;
+  }
 }
 
 /**
diff --git a/hal/src/main/native/athena/DutyCycle.cpp b/hal/src/main/native/athena/DutyCycle.cpp
index 3749a2b..6d70570 100644
--- a/hal/src/main/native/athena/DutyCycle.cpp
+++ b/hal/src/main/native/athena/DutyCycle.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 "hal/DutyCycle.h"
 
diff --git a/hal/src/main/native/athena/DutyCycleInternal.h b/hal/src/main/native/athena/DutyCycleInternal.h
index 33a8ff2..ef49e25 100644
--- a/hal/src/main/native/athena/DutyCycleInternal.h
+++ b/hal/src/main/native/athena/DutyCycleInternal.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
diff --git a/hal/src/main/native/athena/Encoder.cpp b/hal/src/main/native/athena/Encoder.cpp
index be8c203..6edfea3 100644
--- a/hal/src/main/native/athena/Encoder.cpp
+++ b/hal/src/main/native/athena/Encoder.cpp
@@ -1,15 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* 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/Encoder.h"
 
+#include <fmt/format.h>
+
 #include "EncoderInternal.h"
 #include "FPGAEncoder.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/ChipObject.h"
 #include "hal/Counter.h"
@@ -49,6 +49,8 @@
     }
     default:
       *status = PARAMETER_OUT_OF_RANGE;
+      hal::SetLastError(status, fmt::format("Encoding type {} invalid.",
+                                            static_cast<int>(encodingType)));
       return;
   }
 }
@@ -63,15 +65,23 @@
   m_encodingScale = encodingType == HAL_Encoder_k1X ? 1 : 2;
   m_counter =
       HAL_InitializeCounter(HAL_Counter_kExternalDirection, &m_index, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   HAL_SetCounterMaxPeriod(m_counter, 0.5, status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   HAL_SetCounterUpSource(m_counter, digitalSourceHandleA, analogTriggerTypeA,
                          status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   HAL_SetCounterDownSource(m_counter, digitalSourceHandleB, analogTriggerTypeB,
                            status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   if (encodingType == HAL_Encoder_k1X) {
     HAL_SetCounterUpSourceEdge(m_counter, true, false, status);
     HAL_SetCounterAverageSize(m_counter, 1, status);
@@ -176,6 +186,9 @@
 void Encoder::SetSamplesToAverage(int32_t samplesToAverage, int32_t* status) {
   if (samplesToAverage < 1 || samplesToAverage > 127) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, fmt::format("Samples to average must be between "
+                                          "1 and 127 inclusive. Requested {}",
+                                          samplesToAverage));
     return;
   }
   if (m_counter) {
@@ -226,8 +239,7 @@
                                     kNumEncoders + kNumCounters,
                                     HAL_HandleEnum::Encoder>* encoderHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeEncoder() {
   static LimitedClassedHandleResource<HAL_EncoderHandle, Encoder,
                                       kNumEncoders + kNumCounters,
@@ -235,15 +247,16 @@
       eH;
   encoderHandles = &eH;
 }
-}  // namespace init
-}  // namespace hal
+}  // 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;
+  if (!encoder) {
+    return false;
+  }
 
   *fpgaHandle = encoder->m_encoder;
   *counterHandle = encoder->m_counter;
@@ -261,7 +274,9 @@
   auto encoder = std::make_shared<Encoder>(
       digitalSourceHandleA, analogTriggerTypeA, digitalSourceHandleB,
       analogTriggerTypeB, reverseDirection, encodingType, status);
-  if (*status != 0) return HAL_kInvalidHandle;  // return in creation error
+  if (*status != 0) {
+    return HAL_kInvalidHandle;  // return in creation error
+  }
   auto handle = encoderHandles->Allocate(encoder);
   if (handle == HAL_kInvalidHandle) {
     *status = NO_AVAILABLE_RESOURCES;
diff --git a/hal/src/main/native/athena/EncoderInternal.h b/hal/src/main/native/athena/EncoderInternal.h
index bed4ee3..5591a6f 100644
--- a/hal/src/main/native/athena/EncoderInternal.h
+++ b/hal/src/main/native/athena/EncoderInternal.h
@@ -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.
 
 #pragma once
 
diff --git a/hal/src/main/native/athena/FPGAEncoder.cpp b/hal/src/main/native/athena/FPGAEncoder.cpp
index 7f2e107..9965d43 100644
--- a/hal/src/main/native/athena/FPGAEncoder.cpp
+++ b/hal/src/main/native/athena/FPGAEncoder.cpp
@@ -1,16 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "FPGAEncoder.h"
 
 #include <memory>
 
+#include <fmt/format.h>
+
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/handles/LimitedHandleResource.h"
 
@@ -30,16 +30,14 @@
 static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
                              HAL_HandleEnum::FPGAEncoder>* fpgaEncoderHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeFPGAEncoder() {
   static LimitedHandleResource<HAL_FPGAEncoderHandle, Encoder, kNumEncoders,
                                HAL_HandleEnum::FPGAEncoder>
       feH;
   fpgaEncoderHandles = &feH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -198,6 +196,10 @@
   }
   if (samplesToAverage < 1 || samplesToAverage > 127) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(status, fmt::format("Samples to average must be between "
+                                          "1 and 127 inclusive. Requested {}",
+                                          samplesToAverage));
+    return;
   }
   encoder->encoder->writeTimerConfig_AverageSize(samplesToAverage, status);
 }
diff --git a/hal/src/main/native/athena/FPGAEncoder.h b/hal/src/main/native/athena/FPGAEncoder.h
index f29aeae..b401ccd 100644
--- a/hal/src/main/native/athena/FPGAEncoder.h
+++ b/hal/src/main/native/athena/FPGAEncoder.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/athena/FRCDriverStation.cpp b/hal/src/main/native/athena/FRCDriverStation.cpp
index 51fe327..0f4b69b 100644
--- a/hal/src/main/native/athena/FRCDriverStation.cpp
+++ b/hal/src/main/native/athena/FRCDriverStation.cpp
@@ -1,22 +1,21 @@
-/*----------------------------------------------------------------------------*/
-/* 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 <atomic>
 #include <chrono>
 #include <cstdlib>
 #include <cstring>
 #include <limits>
+#include <string>
+#include <string_view>
 
 #include <FRC_NetworkCommunication/FRCComm.h>
 #include <FRC_NetworkCommunication/NetCommRPCProxy_Occur.h>
+#include <fmt/format.h>
 #include <wpi/SafeThread.h>
 #include <wpi/condition_variable.h>
 #include <wpi/mutex.h>
-#include <wpi/raw_ostream.h>
 
 #include "hal/DriverStation.h"
 
@@ -70,15 +69,15 @@
       joystickNum, &buttons->buttons, &buttons->count);
 }
 /**
- * Retrieve the Joystick Descriptor for particular slot
- * @param desc [out] descriptor (data transfer object) to fill in.  desc is
- * filled in regardless of success. In other words, if descriptor is not
- * available, desc is filled in with default values matching the init-values in
- * Java and C++ Driverstation for when caller requests a too-large joystick
- * index.
+ * Retrieve the Joystick Descriptor for particular slot.
  *
+ * @param[out] desc descriptor (data transfer object) to fill in. desc is filled
+ *                  in regardless of success. In other words, if descriptor is
+ *                  not available, desc is filled in with default values
+ *                  matching the init-values in Java and C++ Driverstation for
+ *                  when caller requests a too-large joystick index.
  * @return error code reported from Network Comm back-end.  Zero is good,
- * nonzero is bad.
+ *         nonzero is bad.
  */
 static int32_t HAL_GetJoystickDescriptorInternal(int32_t joystickNum,
                                                  HAL_JoystickDescriptor* desc) {
@@ -126,16 +125,14 @@
 static wpi::condition_variable* newDSDataAvailableCond;
 static int newDSDataAvailableCounter{0};
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeFRCDriverStation() {
   static wpi::mutex newMutex;
   newDSDataAvailableMutex = &newMutex;
   static wpi::condition_variable newCond;
   newDSDataAvailableCond = &newCond;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -161,13 +158,15 @@
   auto curTime = std::chrono::steady_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)) {
-    wpi::StringRef detailsRef{details};
-    wpi::StringRef locationRef{location};
-    wpi::StringRef callStackRef{callStack};
+    std::string_view detailsRef{details};
+    std::string_view locationRef{location};
+    std::string_view callStackRef{callStack};
 
     // 1 tag, 4 timestamp, 2 seqnum
     // 2 numOccur, 4 error code, 1 flags, 6 strlen
@@ -203,14 +202,16 @@
                                                   newCallStack.c_str());
     }
     if (printMsg) {
+      fmt::memory_buffer buf;
       if (location && location[0] != '\0') {
-        wpi::errs() << (isError ? "Error" : "Warning") << " at " << location
-                    << ": ";
+        fmt::format_to(fmt::appender{buf},
+                       "{} at {}: ", isError ? "Error" : "Warning", location);
       }
-      wpi::errs() << details << "\n";
+      fmt::format_to(fmt::appender{buf}, "{}\n", details);
       if (callStack && callStack[0] != '\0') {
-        wpi::errs() << callStack << "\n";
+        fmt::format_to(fmt::appender{buf}, "{}\n", callStack);
       }
+      std::fwrite(buf.data(), buf.size(), 1, stderr);
     }
     if (i == KEEP_MSGS) {
       // replace the oldest one
@@ -230,7 +231,7 @@
 }
 
 int32_t HAL_SendConsoleLine(const char* line) {
-  wpi::StringRef lineRef{line};
+  std::string_view lineRef{line};
   if (lineRef.size() <= 65535) {
     // Send directly
     return FRC_NetworkCommunication_sendConsoleLine(line);
@@ -299,15 +300,16 @@
     name[0] = '\0';
     return name;
   } else {
-    size_t len = std::strlen(joystickDesc.name);
-    char* name = static_cast<char*>(std::malloc(len + 1));
-    std::strncpy(name, joystickDesc.name, len);
-    name[len] = '\0';
+    const size_t len = std::strlen(joystickDesc.name) + 1;
+    char* name = static_cast<char*>(std::malloc(len));
+    std::memcpy(name, joystickDesc.name, len);
     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) {
   HAL_JoystickDescriptor joystickDesc;
@@ -363,21 +365,17 @@
   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;
 }
 
-/**
- * Waits for the newest DS packet to arrive. Note that this is a blocking call.
- */
-void HAL_WaitForDSData(void) { HAL_WaitForDSDataTimeout(0); }
+void HAL_WaitForDSData(void) {
+  HAL_WaitForDSDataTimeout(0);
+}
 
-/**
- * Waits for the newest DS packet to arrive. If timeout is <= 0, this will wait
- * forever. Otherwise, it will wait until either a new packet, or the timeout
- * time has passed. Returns true on new data, false on timeout.
- */
 HAL_Bool HAL_WaitForDSDataTimeout(double timeout) {
   std::unique_lock lock{*newDSDataAvailableMutex};
   int& lastCount = GetThreadLocalLastCount();
@@ -409,7 +407,9 @@
 static void newDataOccur(uint32_t refNum) {
   // Since we could get other values, require our specific handle
   // to signal our threads
-  if (refNum != refNumber) return;
+  if (refNum != refNumber) {
+    return;
+  }
   std::scoped_lock lock{*newDSDataAvailableMutex};
   // Notify all threads
   ++newDSDataAvailableCounter;
@@ -425,11 +425,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;
+  }
 
   // Set up the occur function internally with NetComm
   NetCommRPCProxy_SetOccurFuncPointer(newDataOccur);
@@ -443,6 +447,8 @@
  * Releases the DS Mutex to allow proper shutdown of any threads that are
  * waiting on it.
  */
-void HAL_ReleaseDSMutex(void) { newDataOccur(refNumber); }
+void HAL_ReleaseDSMutex(void) {
+  newDataOccur(refNumber);
+}
 
 }  // extern "C"
diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp
index 17ef0b9..0b6d05e 100644
--- a/hal/src/main/native/athena/HAL.cpp
+++ b/hal/src/main/native/athena/HAL.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/HAL.h"
 
@@ -12,6 +9,7 @@
 #include <unistd.h>
 
 #include <atomic>
+#include <cstdio>
 #include <cstdlib>
 #include <fstream>
 #include <thread>
@@ -19,13 +17,12 @@
 #include <FRC_NetworkCommunication/FRCComm.h>
 #include <FRC_NetworkCommunication/LoadOut.h>
 #include <FRC_NetworkCommunication/UsageReporting.h>
+#include <fmt/format.h>
 #include <wpi/mutex.h>
-#include <wpi/raw_ostream.h>
 #include <wpi/timestamp.h>
 
 #include "HALInitializer.h"
 #include "HALInternal.h"
-#include "ctre/ctre.h"
 #include "hal/ChipObject.h"
 #include "hal/DriverStation.h"
 #include "hal/Errors.h"
@@ -43,6 +40,8 @@
 namespace hal {
 namespace init {
 void InitializeHAL() {
+  InitializeCTREPCM();
+  InitializeREVPH();
   InitializeAddressableLED();
   InitializeAccelerometer();
   InitializeAnalogAccumulator();
@@ -53,7 +52,6 @@
   InitializeAnalogTrigger();
   InitializeCAN();
   InitializeCANAPI();
-  InitializeCompressor();
   InitializeConstants();
   InitializeCounter();
   InitializeDigitalInternal();
@@ -67,14 +65,13 @@
   InitializeInterrupts();
   InitializeMain();
   InitializeNotifier();
-  InitializePCMInternal();
-  InitializePDP();
+  InitializeCTREPDP();
+  InitializeREVPDH();
   InitializePorts();
   InitializePower();
   InitializePWM();
   InitializeRelay();
   InitializeSerialPort();
-  InitializeSolenoid();
   InitializeSPI();
   InitializeThreads();
 }
@@ -95,14 +92,20 @@
 
 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);
 }
 
@@ -110,18 +113,6 @@
   switch (code) {
     case 0:
       return "";
-    case CTR_RxTimeout:
-      return CTR_RxTimeout_MESSAGE;
-    case CTR_TxTimeout:
-      return CTR_TxTimeout_MESSAGE;
-    case CTR_InvalidParamValue:
-      return CTR_InvalidParamValue_MESSAGE;
-    case CTR_UnexpectedArbId:
-      return CTR_UnexpectedArbId_MESSAGE;
-    case CTR_TxFailed:
-      return CTR_TxFailed_MESSAGE;
-    case CTR_SigNotUpdated:
-      return CTR_SigNotUpdated_MESSAGE;
     case NiFpga_Status_FifoTimeout:
       return NiFpga_Status_FifoTimeout_MESSAGE;
     case NiFpga_Status_TransferAborted:
@@ -230,12 +221,26 @@
       return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
     case HAL_LED_CHANNEL_ERROR:
       return HAL_LED_CHANNEL_ERROR_MESSAGE;
+    case HAL_INVALID_DMA_STATE:
+      return HAL_INVALID_DMA_STATE_MESSAGE;
+    case HAL_INVALID_DMA_ADDITION:
+      return HAL_INVALID_DMA_ADDITION_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 HAL_Athena; }
+HAL_RuntimeType HAL_GetRuntimeType(void) {
+  nLoadOut::tTargetClass targetClass = nLoadOut::getTargetClass();
+  if (targetClass == nLoadOut::kTargetClass_RoboRIO2) {
+    return HAL_Runtime_RoboRIO2;
+  }
+  return HAL_Runtime_RoboRIO;
+}
 
 int32_t HAL_GetFPGAVersion(int32_t* status) {
   if (!global) {
@@ -262,35 +267,41 @@
   uint64_t upper1 = global->readLocalTimeUpper(status);
   uint32_t lower = global->readLocalTime(status);
   uint64_t upper2 = global->readLocalTimeUpper(status);
-  if (*status != 0) return 0;
+  if (*status != 0) {
+    return 0;
+  }
   if (upper1 != upper2) {
     // Rolled over between the lower call, reread lower
     lower = global->readLocalTime(status);
-    if (*status != 0) return 0;
+    if (*status != 0) {
+      return 0;
+    }
   }
   return (upper2 << 32) + lower;
 }
 
-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) {
@@ -322,7 +333,9 @@
   std::fstream fs;
   // By making this both in/out, it won't give us an error if it doesnt exist
   fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
-  if (fs.bad()) return false;
+  if (fs.bad()) {
+    return false;
+  }
 
   pid_t pid = 0;
   if (!fs.eof() && !fs.fail()) {
@@ -330,18 +343,19 @@
     // see if the pid is around, but we don't want to mess with init id=1, or
     // ourselves
     if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid()) {
-      wpi::outs() << "Killing previously running FRC program...\n";
+      std::puts("Killing previously running FRC program...");
       kill(pid, SIGTERM);  // try to kill it
       std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
       if (kill(pid, 0) == 0) {
         // still not successful
-        wpi::outs() << "FRC pid " << pid << " did not die within " << timeout
-                    << "ms. Force killing with kill -9\n";
+        fmt::print(
+            "FRC pid {} did not die within {} ms. Force killing with kill -9\n",
+            pid, timeout);
         // Force kill -9
         auto forceKill = kill(pid, SIGKILL);
         if (forceKill != 0) {
           auto errorMsg = std::strerror(forceKill);
-          wpi::outs() << "Kill -9 error: " << errorMsg << "\n";
+          fmt::print("Kill -9 error: {}\n", errorMsg);
         }
         // Give a bit of time for the kill to take place
         std::this_thread::sleep_for(std::chrono::milliseconds(250));
@@ -362,11 +376,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();
 
@@ -374,7 +392,6 @@
 
   setlinebuf(stdin);
   setlinebuf(stdout);
-  wpi::outs().SetUnbuffered();
 
   prctl(PR_SET_PDEATHSIG, SIGTERM);
 
@@ -397,7 +414,9 @@
   global.reset(tGlobal::create(&status));
   watchdog.reset(tSysWatchdog::create(&status));
 
-  if (status != 0) return false;
+  if (status != 0) {
+    return false;
+  }
 
   HAL_InitializeDriverStation();
 
@@ -406,11 +425,11 @@
     int32_t status = 0;
     uint64_t rv = HAL_GetFPGATime(&status);
     if (status != 0) {
-      wpi::errs()
-          << "Call to HAL_GetFPGATime failed in wpi::Now() with status "
-          << status
-          << ". Initialization might have failed. Time will not be correct\n";
-      wpi::errs().flush();
+      fmt::print(stderr,
+                 "Call to HAL_GetFPGATime failed in wpi::Now() with status {}. "
+                 "Initialization might have failed. Time will not be correct\n",
+                 status);
+      std::fflush(stderr);
       return 0u;
     }
     return rv;
@@ -422,6 +441,10 @@
 
 void HAL_Shutdown(void) {}
 
+void HAL_SimPeriodicBefore(void) {}
+
+void HAL_SimPeriodicAfter(void) {}
+
 int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
                    const char* feature) {
   if (feature == nullptr) {
@@ -432,10 +455,4 @@
       resource, instanceNumber, context, feature);
 }
 
-// TODO: HACKS
-// No need for header definitions, as we should not run from user code.
-void NumericArrayResize(void) {}
-void RTSetCleanupProc(void) {}
-void EDVR_CreateReference(void) {}
-
 }  // extern "C"
diff --git a/hal/src/main/native/athena/HALInitializer.cpp b/hal/src/main/native/athena/HALInitializer.cpp
index 5c2242b..50cc9ab 100644
--- a/hal/src/main/native/athena/HALInitializer.cpp
+++ b/hal/src/main/native/athena/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/athena/HALInitializer.h b/hal/src/main/native/athena/HALInitializer.h
index c54660f..182ab5b 100644
--- a/hal/src/main/native/athena/HALInitializer.h
+++ b/hal/src/main/native/athena/HALInitializer.h
@@ -1,23 +1,23 @@
-/*----------------------------------------------------------------------------*/
-/* 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();
 }
 
+extern void InitializeCTREPCM();
+extern void InitializeREVPH();
 extern void InitializeAccelerometer();
 extern void InitializeAddressableLED();
 extern void InitializeAnalogAccumulator();
@@ -28,7 +28,6 @@
 extern void InitializeAnalogTrigger();
 extern void InitializeCAN();
 extern void InitializeCANAPI();
-extern void InitializeCompressor();
 extern void InitializeConstants();
 extern void InitializeCounter();
 extern void InitializeDigitalInternal();
@@ -43,15 +42,13 @@
 extern void InitializeInterrupts();
 extern void InitializeMain();
 extern void InitializeNotifier();
-extern void InitializePCMInternal();
-extern void InitializePDP();
+extern void InitializeCTREPDP();
+extern void InitializeREVPDH();
 extern void InitializePorts();
 extern void InitializePower();
 extern void InitializePWM();
 extern void InitializeRelay();
 extern void InitializeSerialPort();
-extern void InitializeSolenoid();
 extern void InitializeSPI();
 extern void InitializeThreads();
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
diff --git a/hal/src/main/native/athena/HALInternal.h b/hal/src/main/native/athena/HALInternal.h
index e3033bf..64a0dca 100644
--- a/hal/src/main/native/athena/HALInternal.h
+++ b/hal/src/main/native/athena/HALInternal.h
@@ -1,15 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
 #include <stdint.h>
 
+#include <string_view>
+
 namespace hal {
 void ReleaseFPGAInterrupt(int32_t interruptNumber);
-
+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/athena/I2C.cpp b/hal/src/main/native/athena/I2C.cpp
index b72e25e..93e280e 100644
--- a/hal/src/main/native/athena/I2C.cpp
+++ b/hal/src/main/native/athena/I2C.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/I2C.h"
 
@@ -15,8 +12,11 @@
 
 #include <cstring>
 
+#include <fmt/format.h>
+
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "hal/DIO.h"
 #include "hal/HAL.h"
 
@@ -33,44 +33,50 @@
 static HAL_DigitalHandle i2CMXPDigitalHandle1{HAL_kInvalidHandle};
 static HAL_DigitalHandle i2CMXPDigitalHandle2{HAL_kInvalidHandle};
 
-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) {
   hal::init::CheckInit();
   initializeDigital(status);
-  if (*status != 0) return;
+  if (*status != 0) {
+    return;
+  }
 
   if (port < 0 || port > 1) {
-    // Set port out of range error here
+    *status = RESOURCE_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for I2C", 0, 1,
+                                     port);
     return;
   }
 
   if (port == HAL_I2C_kOnboard) {
     std::scoped_lock lock(digitalI2COnBoardMutex);
     i2COnboardObjCount++;
-    if (i2COnboardObjCount > 1) return;
+    if (i2COnboardObjCount > 1) {
+      return;
+    }
     int handle = open("/dev/i2c-2", O_RDWR);
     if (handle < 0) {
-      std::printf("Failed to open onboard i2c bus: %s\n", std::strerror(errno));
+      fmt::print("Failed to open onboard i2c bus: {}\n", std::strerror(errno));
       return;
     }
     i2COnBoardHandle = handle;
   } else {
     std::scoped_lock lock(digitalI2CMXPMutex);
     i2CMXPObjCount++;
-    if (i2CMXPObjCount > 1) return;
+    if (i2CMXPObjCount > 1) {
+      return;
+    }
     if ((i2CMXPDigitalHandle1 = HAL_InitializeDIOPort(
-             HAL_GetPort(24), false, status)) == HAL_kInvalidHandle) {
+             HAL_GetPort(24), false, nullptr, status)) == HAL_kInvalidHandle) {
       return;
     }
     if ((i2CMXPDigitalHandle2 = HAL_InitializeDIOPort(
-             HAL_GetPort(25), false, status)) == HAL_kInvalidHandle) {
+             HAL_GetPort(25), false, nullptr, status)) == HAL_kInvalidHandle) {
       HAL_FreeDIOPort(i2CMXPDigitalHandle1);  // free the first port allocated
       return;
     }
@@ -78,7 +84,7 @@
         digitalSystem->readEnableMXPSpecialFunction(status) | 0xC000, status);
     int handle = open("/dev/i2c-1", O_RDWR);
     if (handle < 0) {
-      std::printf("Failed to open MXP i2c bus: %s\n", std::strerror(errno));
+      fmt::print("Failed to open MXP i2c bus: {}\n", std::strerror(errno));
       return;
     }
     i2CMXPHandle = handle;
@@ -89,7 +95,9 @@
                            const uint8_t* dataToSend, int32_t sendSize,
                            uint8_t* dataReceived, int32_t receiveSize) {
   if (port < 0 || port > 1) {
-    // Set port out of range error here
+    int32_t status = 0;
+    hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 1,
+                                     port);
     return -1;
   }
 
@@ -119,7 +127,9 @@
 int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress,
                      const uint8_t* dataToSend, int32_t sendSize) {
   if (port < 0 || port > 1) {
-    // Set port out of range error here
+    int32_t status = 0;
+    hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 1,
+                                     port);
     return -1;
   }
 
@@ -145,7 +155,9 @@
 int32_t HAL_ReadI2C(HAL_I2CPort port, int32_t deviceAddress, uint8_t* buffer,
                     int32_t count) {
   if (port < 0 || port > 1) {
-    // Set port out of range error here
+    int32_t status = 0;
+    hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 1,
+                                     port);
     return -1;
   }
 
@@ -170,7 +182,9 @@
 
 void HAL_CloseI2C(HAL_I2CPort port) {
   if (port < 0 || port > 1) {
-    // Set port out of range error here
+    int32_t status = 0;
+    hal::SetLastErrorIndexOutOfRange(&status, "Invalid Index for I2C", 0, 1,
+                                     port);
     return;
   }
 
diff --git a/hal/src/main/native/athena/Interrupts.cpp b/hal/src/main/native/athena/Interrupts.cpp
index a330e3c..943a1aa 100644
--- a/hal/src/main/native/athena/Interrupts.cpp
+++ b/hal/src/main/native/athena/Interrupts.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/Interrupts.h"
 
@@ -24,79 +21,29 @@
 using namespace hal;
 
 namespace {
-// Safe thread to allow callbacks to run on their own thread
-class InterruptThread : public wpi::SafeThread {
- public:
-  void Main() {
-    std::unique_lock lock(m_mutex);
-    while (m_active) {
-      m_cond.wait(lock, [&] { return !m_active || m_notify; });
-      if (!m_active) break;
-      m_notify = false;
-      HAL_InterruptHandlerFunction handler = m_handler;
-      uint32_t mask = m_mask;
-      void* param = m_param;
-      lock.unlock();  // don't hold mutex during callback execution
-      handler(mask, param);
-      lock.lock();
-    }
-  }
-
-  bool m_notify = false;
-  HAL_InterruptHandlerFunction m_handler;
-  void* m_param;
-  uint32_t m_mask;
-};
-
-class InterruptThreadOwner : public wpi::SafeThreadOwner<InterruptThread> {
- public:
-  void SetFunc(HAL_InterruptHandlerFunction handler, void* param) {
-    auto thr = GetThread();
-    if (!thr) return;
-    thr->m_handler = handler;
-    thr->m_param = param;
-  }
-
-  void Notify(uint32_t mask) {
-    auto thr = GetThread();
-    if (!thr) return;
-    thr->m_mask = mask;
-    thr->m_notify = true;
-    thr->m_cond.notify_one();
-  }
-};
 
 struct Interrupt {
   std::unique_ptr<tInterrupt> anInterrupt;
   std::unique_ptr<tInterruptManager> manager;
-  std::unique_ptr<InterruptThreadOwner> threadOwner = nullptr;
-  void* param = nullptr;
 };
 
 }  // namespace
 
-static void threadedInterruptHandler(uint32_t mask, void* param) {
-  static_cast<InterruptThreadOwner*>(param)->Notify(mask);
-}
-
 static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
                              HAL_HandleEnum::Interrupt>* interruptHandles;
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeInterrupts() {
   static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
                                HAL_HandleEnum::Interrupt>
       iH;
   interruptHandles = &iH;
 }
-}  // 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) {
@@ -109,24 +56,16 @@
   anInterrupt->anInterrupt.reset(tInterrupt::create(interruptIndex, status));
   anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
   anInterrupt->manager = std::make_unique<tInterruptManager>(
-      (1u << interruptIndex) | (1u << (interruptIndex + 8u)), watcher, status);
+      (1u << interruptIndex) | (1u << (interruptIndex + 8u)), true, status);
   return handle;
 }
 
-void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
-                          int32_t* status) {
+void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {
   auto anInterrupt = interruptHandles->Get(interruptHandle);
   interruptHandles->Free(interruptHandle);
   if (anInterrupt == nullptr) {
-    return nullptr;
+    return;
   }
-
-  if (anInterrupt->manager->isEnabled(status)) {
-    anInterrupt->manager->disable(status);
-  }
-
-  void* param = anInterrupt->param;
-  return param;
 }
 
 int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
@@ -151,31 +90,6 @@
   return result;
 }
 
-void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
-                          int32_t* status) {
-  auto anInterrupt = interruptHandles->Get(interruptHandle);
-  if (anInterrupt == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  if (!anInterrupt->manager->isEnabled(status)) {
-    anInterrupt->manager->enable(status);
-  }
-}
-
-void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
-                           int32_t* status) {
-  auto anInterrupt = interruptHandles->Get(interruptHandle);
-  if (anInterrupt == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-  if (anInterrupt->manager->isEnabled(status)) {
-    anInterrupt->manager->disable(status);
-  }
-}
-
 int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
                                          int32_t* status) {
   auto anInterrupt = interruptHandles->Get(interruptHandle);
@@ -224,40 +138,6 @@
   anInterrupt->anInterrupt->writeConfig_Source_Module(routingModule, status);
 }
 
-void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
-                                HAL_InterruptHandlerFunction handler,
-                                void* param, int32_t* status) {
-  auto anInterrupt = interruptHandles->Get(interruptHandle);
-  if (anInterrupt == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-  anInterrupt->manager->registerHandler(handler, param, status);
-  anInterrupt->param = param;
-}
-
-void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interrupt_handle,
-                                        HAL_InterruptHandlerFunction handler,
-                                        void* param, int32_t* status) {
-  auto anInterrupt = interruptHandles->Get(interrupt_handle);
-  if (anInterrupt == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  anInterrupt->threadOwner = std::make_unique<InterruptThreadOwner>();
-  anInterrupt->threadOwner->Start();
-  anInterrupt->threadOwner->SetFunc(handler, param);
-
-  HAL_AttachInterruptHandler(interrupt_handle, threadedInterruptHandler,
-                             anInterrupt->threadOwner.get(), status);
-
-  if (*status != 0) {
-    anInterrupt->threadOwner = nullptr;
-  }
-  anInterrupt->param = param;
-}
-
 void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
                                   HAL_Bool risingEdge, HAL_Bool fallingEdge,
                                   int32_t* status) {
diff --git a/hal/src/main/native/athena/Notifier.cpp b/hal/src/main/native/athena/Notifier.cpp
index 905c440..d684031 100644
--- a/hal/src/main/native/athena/Notifier.cpp
+++ b/hal/src/main/native/athena/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"
 
@@ -12,6 +9,7 @@
 #include <memory>
 #include <thread>
 
+#include <fmt/core.h>
 #include <wpi/condition_variable.h>
 #include <wpi/mutex.h>
 
@@ -20,6 +18,7 @@
 #include "hal/ChipObject.h"
 #include "hal/Errors.h"
 #include "hal/HAL.h"
+#include "hal/Threads.h"
 #include "hal/handles/UnlimitedHandleResource.h"
 
 using namespace hal;
@@ -29,6 +28,8 @@
 static wpi::mutex notifierMutex;
 static std::unique_ptr<tAlarm> notifierAlarm;
 static std::thread notifierThread;
+static HAL_Bool notifierThreadRealTime = false;
+static int32_t notifierThreadPriority = 0;
 static uint64_t closestTrigger{UINT64_MAX};
 
 namespace {
@@ -78,8 +79,12 @@
 
   // process all notifiers
   notifierHandles->ForEach([&](HAL_NotifierHandle handle, Notifier* notifier) {
-    if (notifier->triggerTime == UINT64_MAX) return;
-    if (currentTime == 0) currentTime = HAL_GetFPGATime(&status);
+    if (notifier->triggerTime == UINT64_MAX) {
+      return;
+    }
+    if (currentTime == 0) {
+      currentTime = HAL_GetFPGATime(&status);
+    }
     std::unique_lock lock(notifier->mutex);
     if (notifier->triggerTime < currentTime) {
       notifier->triggerTime = UINT64_MAX;
@@ -105,41 +110,61 @@
   tInterruptManager manager{1 << kTimerInterruptNumber, true, &status};
   while (notifierRunning) {
     auto triggeredMask = manager.watch(10000, false, &status);
-    if (!notifierRunning) break;
-    if (triggeredMask == 0) continue;
+    if (!notifierRunning) {
+      break;
+    }
+    if (triggeredMask == 0)
+      continue;
     alarmCallback();
   }
 }
 
 static void cleanupNotifierAtExit() {
   int32_t status = 0;
-  if (notifierAlarm) notifierAlarm->writeEnable(false, &status);
+  if (notifierAlarm)
+    notifierAlarm->writeEnable(false, &status);
   notifierAlarm = nullptr;
   notifierRunning = false;
   hal::ReleaseFPGAInterrupt(kTimerInterruptNumber);
-  if (notifierThread.joinable()) notifierThread.join();
+  if (notifierThread.joinable()) {
+    notifierThread.join();
+  }
 }
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeNotifier() {
   static NotifierHandleContainer nH;
   notifierHandles = &nH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
 HAL_NotifierHandle HAL_InitializeNotifier(int32_t* status) {
   hal::init::CheckInit();
-  if (!notifierAtexitRegistered.test_and_set())
+  if (!notifierAtexitRegistered.test_and_set()) {
     std::atexit(cleanupNotifierAtExit);
+  }
 
   if (notifierRefCount.fetch_add(1) == 0) {
     std::scoped_lock lock(notifierMutex);
     notifierRunning = true;
     notifierThread = std::thread(notifierThreadMain);
+
+    auto native = notifierThread.native_handle();
+    HAL_SetThreadPriority(&native, notifierThreadRealTime,
+                          notifierThreadPriority, status);
+    if (*status == HAL_THREAD_PRIORITY_ERROR) {
+      *status = 0;
+      fmt::print("{}: HAL Notifier thread\n",
+                 HAL_THREAD_PRIORITY_ERROR_MESSAGE);
+    }
+    if (*status == HAL_THREAD_PRIORITY_RANGE_ERROR) {
+      *status = 0;
+      fmt::print("{}: HAL Notifier thread\n",
+                 HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE);
+    }
+
     notifierAlarm.reset(tAlarm::create(status));
   }
 
@@ -152,12 +177,26 @@
   return handle;
 }
 
+HAL_Bool HAL_SetNotifierThreadPriority(HAL_Bool realTime, int32_t priority,
+                                       int32_t* status) {
+  std::scoped_lock lock(notifierMutex);
+  notifierThreadRealTime = realTime;
+  notifierThreadPriority = priority;
+  if (notifierThread.joinable()) {
+    auto native = notifierThread.native_handle();
+    return HAL_SetThreadPriority(&native, realTime, priority, status);
+  } else {
+    return true;
+  }
+}
+
 void HAL_SetNotifierName(HAL_NotifierHandle notifierHandle, const char* name,
                          int32_t* status) {}
 
 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);
@@ -170,7 +209,8 @@
 
 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...
   {
@@ -187,10 +227,13 @@
     // here (the atomic fetch_sub will prevent multiple parallel entries
     // into this function)
 
-    if (notifierAlarm) notifierAlarm->writeEnable(false, status);
+    if (notifierAlarm)
+      notifierAlarm->writeEnable(false, status);
     notifierRunning = false;
     hal::ReleaseFPGAInterrupt(kTimerInterruptNumber);
-    if (notifierThread.joinable()) notifierThread.join();
+    if (notifierThread.joinable()) {
+      notifierThread.join();
+    }
 
     std::scoped_lock lock(notifierMutex);
     notifierAlarm = nullptr;
@@ -201,7 +244,8 @@
 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);
@@ -218,14 +262,16 @@
     notifierAlarm->writeTriggerTime(static_cast<uint32_t>(closestTrigger),
                                     status);
     // Enable the alarm.
-    if (!wasActive) notifierAlarm->writeEnable(true, status);
+    if (!wasActive)
+      notifierAlarm->writeEnable(true, status);
   }
 }
 
 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);
@@ -236,7 +282,8 @@
 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 lock(notifier->mutex);
   notifier->cond.wait(lock, [&] {
     return !notifier->active || notifier->triggeredTime != UINT64_MAX;
diff --git a/hal/src/main/native/athena/PCMInternal.cpp b/hal/src/main/native/athena/PCMInternal.cpp
deleted file mode 100644
index c81dc1a..0000000
--- a/hal/src/main/native/athena/PCMInternal.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "PCMInternal.h"
-
-#include "HALInitializer.h"
-#include "hal/Errors.h"
-#include "hal/Solenoid.h"
-
-namespace hal {
-
-std::unique_ptr<PCM> PCM_modules[kNumPCMModules];
-
-namespace init {
-void InitializePCMInternal() {
-  for (int i = 0; i < kNumPCMModules; i++) {
-    PCM_modules[i] = nullptr;
-  }
-}
-}  // namespace init
-
-void initializePCM(int32_t module, int32_t* status) {
-  hal::init::CheckInit();
-  if (!HAL_CheckSolenoidModule(module)) {
-    *status = RESOURCE_OUT_OF_RANGE;
-    return;
-  }
-  if (!PCM_modules[module]) {
-    PCM_modules[module] = std::make_unique<PCM>(module);
-  }
-}
-
-}  // namespace hal
diff --git a/hal/src/main/native/athena/PCMInternal.h b/hal/src/main/native/athena/PCMInternal.h
deleted file mode 100644
index a9d076c..0000000
--- a/hal/src/main/native/athena/PCMInternal.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "PortsInternal.h"
-#include "ctre/PCM.h"
-#include "hal/Errors.h"
-#include "hal/Solenoid.h"
-
-namespace hal {
-
-extern std::unique_ptr<PCM> PCM_modules[kNumPCMModules];
-
-static inline bool checkPCMInit(int32_t module, int32_t* status) {
-  if (!HAL_CheckSolenoidModule(module)) {
-    *status = RESOURCE_OUT_OF_RANGE;
-    return false;
-  }
-  if (!PCM_modules[module]) {
-    *status = INCOMPATIBLE_STATE;
-    return false;
-  }
-  return true;
-}
-
-void initializePCM(int32_t module, int32_t* status);
-
-}  // namespace hal
diff --git a/hal/src/main/native/athena/PWM.cpp b/hal/src/main/native/athena/PWM.cpp
index a3b141c..19a3b83 100644
--- a/hal/src/main/native/athena/PWM.cpp
+++ b/hal/src/main/native/athena/PWM.cpp
@@ -1,20 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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/PWM.h"
 
+#include <algorithm>
 #include <cmath>
+#include <cstdio>
 #include <thread>
 
-#include <wpi/raw_ostream.h>
-
 #include "ConstantsInternal.h"
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/cpp/fpga_clock.h"
 #include "hal/handles/HandlesInternal.h"
@@ -61,24 +59,27 @@
   return GetMaxPositivePwm(port) - GetMinNegativePwm(port);
 }  ///< The scale for positions.
 
-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();
   initializeDigital(status);
 
-  if (*status != 0) return HAL_kInvalidHandle;
+  if (*status != 0) {
+    return HAL_kInvalidHandle;
+  }
 
   int16_t channel = getPortHandleChannel(portHandle);
   if (channel == InvalidHandleIndex || channel >= kNumPWMChannels) {
-    *status = PARAMETER_OUT_OF_RANGE;
+    *status = RESOURCE_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
+                                     kNumPWMChannels, channel);
     return HAL_kInvalidHandle;
   }
 
@@ -90,16 +91,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", origChannel,
+                                           port->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for PWM", 0,
+                                       kNumPWMChannels, origChannel);
+    }
     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;
@@ -115,6 +120,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) {
@@ -131,8 +138,8 @@
   while (port.use_count() != 1) {
     auto current = hal::fpga_clock::now();
     if (start + std::chrono::seconds(1) < current) {
-      wpi::outs() << "PWM handle free timeout\n";
-      wpi::outs().flush();
+      std::puts("PWM handle free timeout");
+      std::fflush(stdout);
       break;
     }
     std::this_thread::yield();
@@ -163,7 +170,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);
@@ -277,13 +286,13 @@
   if (speed == 0.0) {
     rawValue = GetCenterPwm(dPort);
   } else if (speed > 0.0) {
-    rawValue = static_cast<int32_t>(
-        speed * static_cast<double>(GetPositiveScaleFactor(dPort)) +
-        static_cast<double>(GetMinPositivePwm(dPort)) + 0.5);
+    rawValue =
+        std::lround(speed * static_cast<double>(GetPositiveScaleFactor(dPort)) +
+                    static_cast<double>(GetMinPositivePwm(dPort)));
   } else {
-    rawValue = static_cast<int32_t>(
-        speed * static_cast<double>(GetNegativeScaleFactor(dPort)) +
-        static_cast<double>(GetMaxNegativePwm(dPort)) + 0.5);
+    rawValue =
+        std::lround(speed * static_cast<double>(GetNegativeScaleFactor(dPort)) +
+                    static_cast<double>(GetMaxNegativePwm(dPort)));
   }
 
   if (!((rawValue >= GetMinNegativePwm(dPort)) &&
@@ -359,7 +368,9 @@
   }
 
   int32_t value = HAL_GetPWMRaw(pwmPortHandle, status);
-  if (*status != 0) return 0;
+  if (*status != 0) {
+    return 0;
+  }
   DigitalPort* dPort = port.get();
 
   if (value == kPwmDisabled) {
@@ -391,7 +402,9 @@
   }
 
   int32_t value = HAL_GetPWMRaw(pwmPortHandle, status);
-  if (*status != 0) return 0;
+  if (*status != 0) {
+    return 0;
+  }
   DigitalPort* dPort = port.get();
 
   if (value < GetMinNegativePwm(dPort)) {
@@ -433,22 +446,30 @@
 
 int32_t HAL_GetPWMLoopTiming(int32_t* status) {
   initializeDigital(status);
-  if (*status != 0) return 0;
+  if (*status != 0) {
+    return 0;
+  }
   return pwmSystem->readLoopTiming(status);
 }
 
 uint64_t HAL_GetPWMCycleStartTime(int32_t* status) {
   initializeDigital(status);
-  if (*status != 0) return 0;
+  if (*status != 0) {
+    return 0;
+  }
 
   uint64_t upper1 = pwmSystem->readCycleStartTimeUpper(status);
   uint32_t lower = pwmSystem->readCycleStartTime(status);
   uint64_t upper2 = pwmSystem->readCycleStartTimeUpper(status);
-  if (*status != 0) return 0;
+  if (*status != 0) {
+    return 0;
+  }
   if (upper1 != upper2) {
     // Rolled over between the lower call, reread lower
     lower = pwmSystem->readCycleStartTime(status);
-    if (*status != 0) return 0;
+    if (*status != 0) {
+      return 0;
+    }
   }
   return (upper2 << 32) + lower;
 }
diff --git a/hal/src/main/native/athena/Ports.cpp b/hal/src/main/native/athena/Ports.cpp
index 47bd400..d27ecbd 100644
--- a/hal/src/main/native/athena/Ports.cpp
+++ b/hal/src/main/native/athena/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,33 +8,83 @@
 
 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/athena/PortsInternal.h b/hal/src/main/native/athena/PortsInternal.h
index 98fc690..18ce569 100644
--- a/hal/src/main/native/athena/PortsInternal.h
+++ b/hal/src/main/native/athena/PortsInternal.h
@@ -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.
 
 #pragma once
 
@@ -31,11 +28,15 @@
 constexpr int32_t kNumInterrupts = tInterrupt::kNumSystems;
 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 = tDutyCycle::kNumSystems;
 constexpr int32_t kNumAddressableLEDs = tLED::kNumSystems;
+constexpr int32_t kNumREVPHModules = 63;
+constexpr int32_t kNumREVPHChannels = 16;
 
 }  // namespace hal
diff --git a/hal/src/main/native/athena/Power.cpp b/hal/src/main/native/athena/Power.cpp
index 2cf4d33..e911d5d 100644
--- a/hal/src/main/native/athena/Power.cpp
+++ b/hal/src/main/native/athena/Power.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/Power.h"
 
@@ -27,11 +24,9 @@
 
 }  // namespace hal
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializePower() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -108,4 +103,22 @@
       power->readFaultCounts_OverCurrentFaultCount3V3(status));
 }
 
+void HAL_SetBrownoutVoltage(double voltage, int32_t* status) {
+  initializePower(status);
+  if (voltage < 0) {
+    voltage = 0;
+  }
+  if (voltage > 50) {
+    voltage = 50;
+  }
+  power->writeBrownoutVoltage250mV(static_cast<unsigned char>(voltage * 4),
+                                   status);
+}
+
+double HAL_GetBrownoutVoltage(int32_t* status) {
+  initializePower(status);
+  auto brownout = power->readBrownoutVoltage250mV(status);
+  return brownout / 4.0;
+}
+
 }  // extern "C"
diff --git a/hal/src/main/native/athena/PowerDistribution.cpp b/hal/src/main/native/athena/PowerDistribution.cpp
new file mode 100644
index 0000000..f7fe88f
--- /dev/null
+++ b/hal/src/main/native/athena/PowerDistribution.cpp
@@ -0,0 +1,208 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 "CTREPDP.h"
+#include "HALInternal.h"
+#include "PortsInternal.h"
+#include "REVPDH.h"
+#include "hal/Errors.h"
+#include "hal/handles/HandlesInternal.h"
+
+using namespace hal;
+
+extern "C" {
+
+HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
+    int32_t moduleNumber, HAL_PowerDistributionType type,
+    const char* allocationLocation, int32_t* status) {
+  if (type == HAL_PowerDistributionType::HAL_PowerDistributionType_kAutomatic) {
+    type = HAL_PowerDistributionType::HAL_PowerDistributionType_kCTRE;
+  }
+
+  if (type == HAL_PowerDistributionType::HAL_PowerDistributionType_kCTRE) {
+    if (moduleNumber == HAL_DEFAULT_POWER_DISTRIBUTION_MODULE) {
+      moduleNumber = 0;
+    }
+    return static_cast<HAL_PowerDistributionHandle>(
+        HAL_InitializePDP(moduleNumber, allocationLocation, status));  // TODO
+  } else {
+    if (moduleNumber == HAL_DEFAULT_POWER_DISTRIBUTION_MODULE) {
+      moduleNumber = 1;
+    }
+    return static_cast<HAL_PowerDistributionHandle>(
+        HAL_REV_InitializePDH(moduleNumber, allocationLocation, status));
+  }
+}
+
+#define IsCtre(handle) ::hal::isHandleType(handle, HAL_HandleEnum::CTREPDP)
+
+void HAL_CleanPowerDistribution(HAL_PowerDistributionHandle handle) {
+  if (IsCtre(handle)) {
+    HAL_CleanPDP(handle);
+  } else {
+    HAL_REV_FreePDH(handle);
+  }
+}
+
+int32_t HAL_GetPowerDistributionModuleNumber(HAL_PowerDistributionHandle handle,
+                                             int32_t* status) {
+  if (IsCtre(handle)) {
+    return HAL_GetPDPModuleNumber(handle, status);
+  } else {
+    return HAL_REV_GetPDHModuleNumber(handle, status);
+  }
+}
+
+HAL_Bool HAL_CheckPowerDistributionChannel(HAL_PowerDistributionHandle handle,
+                                           int32_t channel) {
+  if (IsCtre(handle)) {
+    return HAL_CheckPDPChannel(channel);
+  } else {
+    return HAL_REV_CheckPDHChannelNumber(channel);
+  }
+}
+
+HAL_Bool HAL_CheckPowerDistributionModule(int32_t module,
+                                          HAL_PowerDistributionType type) {
+  if (type == HAL_PowerDistributionType::HAL_PowerDistributionType_kCTRE) {
+    return HAL_CheckPDPModule(module);
+  } else {
+    return HAL_REV_CheckPDHModuleNumber(module);
+  }
+}
+
+HAL_PowerDistributionType HAL_GetPowerDistributionType(
+    HAL_PowerDistributionHandle handle, int32_t* status) {
+  return IsCtre(handle)
+             ? HAL_PowerDistributionType::HAL_PowerDistributionType_kCTRE
+             : HAL_PowerDistributionType::HAL_PowerDistributionType_kRev;
+}
+
+int32_t HAL_GetPowerDistributionNumChannels(HAL_PowerDistributionHandle handle,
+                                            int32_t* status) {
+  if (IsCtre(handle)) {
+    return kNumCTREPDPChannels;
+  } else {
+    return kNumREVPDHChannels;
+  }
+}
+
+double HAL_GetPowerDistributionTemperature(HAL_PowerDistributionHandle handle,
+                                           int32_t* status) {
+  if (IsCtre(handle)) {
+    return HAL_GetPDPTemperature(handle, status);
+  } else {
+    // Not supported
+    return 0;
+  }
+}
+
+double HAL_GetPowerDistributionVoltage(HAL_PowerDistributionHandle handle,
+                                       int32_t* status) {
+  if (IsCtre(handle)) {
+    return HAL_GetPDPVoltage(handle, status);
+  } else {
+    return HAL_REV_GetPDHSupplyVoltage(handle, status);
+  }
+}
+
+double HAL_GetPowerDistributionChannelCurrent(
+    HAL_PowerDistributionHandle handle, int32_t channel, int32_t* status) {
+  if (IsCtre(handle)) {
+    return HAL_GetPDPChannelCurrent(handle, channel, status);
+  } else {
+    return HAL_REV_GetPDHChannelCurrent(handle, channel, status);
+  }
+}
+
+void HAL_GetPowerDistributionAllChannelCurrents(
+    HAL_PowerDistributionHandle handle, double* currents,
+    int32_t currentsLength, int32_t* status) {
+  if (IsCtre(handle)) {
+    if (currentsLength < kNumCTREPDPChannels) {
+      *status = PARAMETER_OUT_OF_RANGE;
+      SetLastError(status, "Output array not large enough");
+      return;
+    }
+    return HAL_GetPDPAllChannelCurrents(handle, currents, status);
+  } else {
+    if (currentsLength < kNumREVPDHChannels) {
+      *status = PARAMETER_OUT_OF_RANGE;
+      SetLastError(status, "Output array not large enough");
+      return;
+    }
+    return HAL_REV_GetPDHAllChannelCurrents(handle, currents, status);
+  }
+}
+
+double HAL_GetPowerDistributionTotalCurrent(HAL_PowerDistributionHandle handle,
+                                            int32_t* status) {
+  if (IsCtre(handle)) {
+    return HAL_GetPDPTotalCurrent(handle, status);
+  } else {
+    return HAL_REV_GetPDHTotalCurrent(handle, status);
+  }
+}
+
+double HAL_GetPowerDistributionTotalPower(HAL_PowerDistributionHandle handle,
+                                          int32_t* status) {
+  if (IsCtre(handle)) {
+    return HAL_GetPDPTotalPower(handle, status);
+  } else {
+    // Not currently supported
+    return 0;
+  }
+}
+
+double HAL_GetPowerDistributionTotalEnergy(HAL_PowerDistributionHandle handle,
+                                           int32_t* status) {
+  if (IsCtre(handle)) {
+    return HAL_GetPDPTotalEnergy(handle, status);
+  } else {
+    // Not currently supported
+    return 0;
+  }
+}
+
+void HAL_ResetPowerDistributionTotalEnergy(HAL_PowerDistributionHandle handle,
+                                           int32_t* status) {
+  if (IsCtre(handle)) {
+    HAL_ResetPDPTotalEnergy(handle, status);
+  } else {
+    // Not supported
+  }
+}
+
+void HAL_ClearPowerDistributionStickyFaults(HAL_PowerDistributionHandle handle,
+                                            int32_t* status) {
+  if (IsCtre(handle)) {
+    HAL_ClearPDPStickyFaults(handle, status);
+  } else {
+    HAL_REV_ClearPDHFaults(handle, status);
+  }
+}
+
+void HAL_SetPowerDistributionSwitchableChannel(
+    HAL_PowerDistributionHandle handle, HAL_Bool enabled, int32_t* status) {
+  if (IsCtre(handle)) {
+    // No-op on CTRE
+    return;
+  } else {
+    HAL_REV_SetPDHSwitchableChannel(handle, enabled, status);
+  }
+}
+
+HAL_Bool HAL_GetPowerDistributionSwitchableChannel(
+    HAL_PowerDistributionHandle handle, int32_t* status) {
+  if (IsCtre(handle)) {
+    // No-op on CTRE
+    return false;
+  } else {
+    return HAL_REV_GetPDHSwitchableChannelState(handle, status);
+  }
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/REVPDH.cpp b/hal/src/main/native/athena/REVPDH.cpp
new file mode 100644
index 0000000..9ad45b5
--- /dev/null
+++ b/hal/src/main/native/athena/REVPDH.cpp
@@ -0,0 +1,798 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 "REVPDH.h"
+
+#include <hal/CANAPI.h>
+#include <hal/CANAPITypes.h>
+#include <hal/Errors.h>
+#include <hal/handles/HandlesInternal.h>
+#include <hal/handles/IndexedHandleResource.h>
+
+#include <cstring>
+
+#include <fmt/format.h>
+
+#include "HALInitializer.h"
+#include "HALInternal.h"
+#include "PortsInternal.h"
+#include "rev/PDHFrames.h"
+
+using namespace hal;
+
+static constexpr HAL_CANManufacturer manufacturer =
+    HAL_CANManufacturer::HAL_CAN_Man_kREV;
+
+static constexpr HAL_CANDeviceType deviceType =
+    HAL_CANDeviceType::HAL_CAN_Dev_kPowerDistribution;
+
+static constexpr int32_t kDefaultControlPeriod = 50;
+
+namespace {
+
+struct REV_PDHObj {
+  int32_t controlPeriod;
+  HAL_CANHandle hcan;
+  std::string previousAllocation;
+};
+
+}  // namespace
+
+static constexpr uint32_t APIFromExtId(uint32_t extId) {
+  return (extId >> 6) & 0x3FF;
+}
+
+static constexpr uint32_t PDH_SWITCH_CHANNEL_SET_FRAME_API =
+    APIFromExtId(PDH_SWITCH_CHANNEL_SET_FRAME_ID);
+
+static constexpr uint32_t PDH_STATUS0_FRAME_API =
+    APIFromExtId(PDH_STATUS0_FRAME_ID);
+static constexpr uint32_t PDH_STATUS1_FRAME_API =
+    APIFromExtId(PDH_STATUS1_FRAME_ID);
+static constexpr uint32_t PDH_STATUS2_FRAME_API =
+    APIFromExtId(PDH_STATUS2_FRAME_ID);
+static constexpr uint32_t PDH_STATUS3_FRAME_API =
+    APIFromExtId(PDH_STATUS3_FRAME_ID);
+static constexpr uint32_t PDH_STATUS4_FRAME_API =
+    APIFromExtId(PDH_STATUS4_FRAME_ID);
+
+static constexpr uint32_t PDH_CLEAR_FAULTS_FRAME_API =
+    APIFromExtId(PDH_CLEAR_FAULTS_FRAME_ID);
+
+static constexpr uint32_t PDH_IDENTIFY_FRAME_API =
+    APIFromExtId(PDH_IDENTIFY_FRAME_ID);
+
+static constexpr uint32_t PDH_VERSION_FRAME_API =
+    APIFromExtId(PDH_VERSION_FRAME_ID);
+
+static constexpr uint32_t PDH_CONFIGURE_HR_CHANNEL_FRAME_API =
+    APIFromExtId(PDH_CONFIGURE_HR_CHANNEL_FRAME_ID);
+
+static constexpr int32_t kPDHFrameStatus0Timeout = 20;
+static constexpr int32_t kPDHFrameStatus1Timeout = 20;
+static constexpr int32_t kPDHFrameStatus2Timeout = 20;
+static constexpr int32_t kPDHFrameStatus3Timeout = 20;
+static constexpr int32_t kPDHFrameStatus4Timeout = 20;
+
+static IndexedHandleResource<HAL_REVPDHHandle, REV_PDHObj, kNumREVPDHModules,
+                             HAL_HandleEnum::REVPDH>* REVPDHHandles;
+
+namespace hal::init {
+void InitializeREVPDH() {
+  static IndexedHandleResource<HAL_REVPDHHandle, REV_PDHObj, kNumREVPDHModules,
+                               HAL_HandleEnum::REVPDH>
+      rH;
+  REVPDHHandles = &rH;
+}
+}  // namespace hal::init
+
+extern "C" {
+
+static PDH_status0_t HAL_REV_ReadPDHStatus0(HAL_CANHandle hcan,
+                                            int32_t* status) {
+  uint8_t packedData[8] = {0};
+  int32_t length = 0;
+  uint64_t timestamp = 0;
+  PDH_status0_t result = {};
+
+  HAL_ReadCANPacketTimeout(hcan, PDH_STATUS0_FRAME_API, packedData, &length,
+                           &timestamp, kPDHFrameStatus0Timeout * 2, status);
+
+  if (*status != 0) {
+    return result;
+  }
+
+  PDH_status0_unpack(&result, packedData, PDH_STATUS0_LENGTH);
+
+  return result;
+}
+
+static PDH_status1_t HAL_REV_ReadPDHStatus1(HAL_CANHandle hcan,
+                                            int32_t* status) {
+  uint8_t packedData[8] = {0};
+  int32_t length = 0;
+  uint64_t timestamp = 0;
+  PDH_status1_t result = {};
+
+  HAL_ReadCANPacketTimeout(hcan, PDH_STATUS1_FRAME_API, packedData, &length,
+                           &timestamp, kPDHFrameStatus1Timeout * 2, status);
+
+  if (*status != 0) {
+    return result;
+  }
+
+  PDH_status1_unpack(&result, packedData, PDH_STATUS1_LENGTH);
+
+  return result;
+}
+
+static PDH_status2_t HAL_REV_ReadPDHStatus2(HAL_CANHandle hcan,
+                                            int32_t* status) {
+  uint8_t packedData[8] = {0};
+  int32_t length = 0;
+  uint64_t timestamp = 0;
+  PDH_status2_t result = {};
+
+  HAL_ReadCANPacketTimeout(hcan, PDH_STATUS2_FRAME_API, packedData, &length,
+                           &timestamp, kPDHFrameStatus2Timeout * 2, status);
+
+  if (*status != 0) {
+    return result;
+  }
+
+  PDH_status2_unpack(&result, packedData, PDH_STATUS2_LENGTH);
+
+  return result;
+}
+
+static PDH_status3_t HAL_REV_ReadPDHStatus3(HAL_CANHandle hcan,
+                                            int32_t* status) {
+  uint8_t packedData[8] = {0};
+  int32_t length = 0;
+  uint64_t timestamp = 0;
+  PDH_status3_t result = {};
+
+  HAL_ReadCANPacketTimeout(hcan, PDH_STATUS3_FRAME_API, packedData, &length,
+                           &timestamp, kPDHFrameStatus3Timeout * 2, status);
+
+  if (*status != 0) {
+    return result;
+  }
+
+  PDH_status3_unpack(&result, packedData, PDH_STATUS3_LENGTH);
+
+  return result;
+}
+
+static PDH_status4_t HAL_REV_ReadPDHStatus4(HAL_CANHandle hcan,
+                                            int32_t* status) {
+  uint8_t packedData[8] = {0};
+  int32_t length = 0;
+  uint64_t timestamp = 0;
+  PDH_status4_t result = {};
+
+  HAL_ReadCANPacketTimeout(hcan, PDH_STATUS4_FRAME_API, packedData, &length,
+                           &timestamp, kPDHFrameStatus4Timeout * 2, status);
+
+  if (*status != 0) {
+    return result;
+  }
+
+  PDH_status4_unpack(&result, packedData, PDH_STATUS4_LENGTH);
+
+  return result;
+}
+
+/**
+ * Helper function for the individual getter functions for status 4
+ */
+PDH_status4_t HAL_REV_GetPDHStatus4(HAL_REVPDHHandle handle, int32_t* status) {
+  PDH_status4_t statusFrame = {};
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return statusFrame;
+  }
+
+  statusFrame = HAL_REV_ReadPDHStatus4(hpdh->hcan, status);
+  return statusFrame;
+}
+
+HAL_REVPDHHandle HAL_REV_InitializePDH(int32_t module,
+                                       const char* allocationLocation,
+                                       int32_t* status) {
+  hal::init::CheckInit();
+  if (!HAL_REV_CheckPDHModuleNumber(module)) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return HAL_kInvalidHandle;
+  }
+
+  HAL_REVPDHHandle handle;
+  auto hpdh = REVPDHHandles->Allocate(module, &handle, status);
+  if (*status != 0) {
+    if (hpdh) {
+      hal::SetLastErrorPreviouslyAllocated(status, "REV PDH", module,
+                                           hpdh->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PDH", 0,
+                                       kNumREVPDHModules, module);
+    }
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+  }
+
+  HAL_CANHandle hcan =
+      HAL_InitializeCAN(manufacturer, module, deviceType, status);
+
+  if (*status != 0) {
+    REVPDHHandles->Free(handle);
+    return HAL_kInvalidHandle;
+  }
+
+  hpdh->previousAllocation = allocationLocation ? allocationLocation : "";
+  hpdh->hcan = hcan;
+  hpdh->controlPeriod = kDefaultControlPeriod;
+
+  return handle;
+}
+
+void HAL_REV_FreePDH(HAL_REVPDHHandle handle) {
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    return;
+  }
+
+  HAL_CleanCAN(hpdh->hcan);
+
+  REVPDHHandles->Free(handle);
+}
+
+int32_t HAL_REV_GetPDHModuleNumber(HAL_REVPDHHandle handle, int32_t* status) {
+  return hal::getHandleIndex(handle);
+}
+
+HAL_Bool HAL_REV_CheckPDHModuleNumber(int32_t module) {
+  return ((module >= 1) && (module < kNumREVPDHModules)) ? 1 : 0;
+}
+
+HAL_Bool HAL_REV_CheckPDHChannelNumber(int32_t channel) {
+  return ((channel >= 0) && (channel < kNumREVPDHChannels)) ? 1 : 0;
+}
+
+double HAL_REV_GetPDHChannelCurrent(HAL_REVPDHHandle handle, int32_t channel,
+                                    int32_t* status) {
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  if (!HAL_REV_CheckPDHChannelNumber(channel)) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return 0;
+  }
+
+  // Determine what periodic status the channel is in
+  if (channel < 6) {
+    // Periodic status 0
+    PDH_status0_t statusFrame = HAL_REV_ReadPDHStatus0(hpdh->hcan, status);
+    switch (channel) {
+      case 0:
+        return PDH_status0_channel_0_current_decode(
+            statusFrame.channel_0_current);
+      case 1:
+        return PDH_status0_channel_1_current_decode(
+            statusFrame.channel_1_current);
+      case 2:
+        return PDH_status0_channel_2_current_decode(
+            statusFrame.channel_2_current);
+      case 3:
+        return PDH_status0_channel_3_current_decode(
+            statusFrame.channel_3_current);
+      case 4:
+        return PDH_status0_channel_4_current_decode(
+            statusFrame.channel_4_current);
+      case 5:
+        return PDH_status0_channel_5_current_decode(
+            statusFrame.channel_5_current);
+    }
+  } else if (channel < 12) {
+    // Periodic status 1
+    PDH_status1_t statusFrame = HAL_REV_ReadPDHStatus1(hpdh->hcan, status);
+    switch (channel) {
+      case 6:
+        return PDH_status1_channel_6_current_decode(
+            statusFrame.channel_6_current);
+      case 7:
+        return PDH_status1_channel_7_current_decode(
+            statusFrame.channel_7_current);
+      case 8:
+        return PDH_status1_channel_8_current_decode(
+            statusFrame.channel_8_current);
+      case 9:
+        return PDH_status1_channel_9_current_decode(
+            statusFrame.channel_9_current);
+      case 10:
+        return PDH_status1_channel_10_current_decode(
+            statusFrame.channel_10_current);
+      case 11:
+        return PDH_status1_channel_11_current_decode(
+            statusFrame.channel_11_current);
+    }
+  } else if (channel < 18) {
+    // Periodic status 2
+    PDH_status2_t statusFrame = HAL_REV_ReadPDHStatus2(hpdh->hcan, status);
+    switch (channel) {
+      case 12:
+        return PDH_status2_channel_12_current_decode(
+            statusFrame.channel_12_current);
+      case 13:
+        return PDH_status2_channel_13_current_decode(
+            statusFrame.channel_13_current);
+      case 14:
+        return PDH_status2_channel_14_current_decode(
+            statusFrame.channel_14_current);
+      case 15:
+        return PDH_status2_channel_15_current_decode(
+            statusFrame.channel_15_current);
+      case 16:
+        return PDH_status2_channel_16_current_decode(
+            statusFrame.channel_16_current);
+      case 17:
+        return PDH_status2_channel_17_current_decode(
+            statusFrame.channel_17_current);
+    }
+  } else if (channel < 24) {
+    // Periodic status 3
+    PDH_status3_t statusFrame = HAL_REV_ReadPDHStatus3(hpdh->hcan, status);
+    switch (channel) {
+      case 18:
+        return PDH_status3_channel_18_current_decode(
+            statusFrame.channel_18_current);
+      case 19:
+        return PDH_status3_channel_19_current_decode(
+            statusFrame.channel_19_current);
+      case 20:
+        return PDH_status3_channel_20_current_decode(
+            statusFrame.channel_20_current);
+      case 21:
+        return PDH_status3_channel_21_current_decode(
+            statusFrame.channel_21_current);
+      case 22:
+        return PDH_status3_channel_22_current_decode(
+            statusFrame.channel_22_current);
+      case 23:
+        return PDH_status3_channel_23_current_decode(
+            statusFrame.channel_23_current);
+    }
+  }
+  return 0;
+}
+
+void HAL_REV_GetPDHAllChannelCurrents(HAL_REVPDHHandle handle, double* currents,
+                                      int32_t* status) {
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  PDH_status0_t statusFrame0 = HAL_REV_ReadPDHStatus0(hpdh->hcan, status);
+  PDH_status1_t statusFrame1 = HAL_REV_ReadPDHStatus1(hpdh->hcan, status);
+  PDH_status2_t statusFrame2 = HAL_REV_ReadPDHStatus2(hpdh->hcan, status);
+  PDH_status3_t statusFrame3 = HAL_REV_ReadPDHStatus3(hpdh->hcan, status);
+
+  currents[0] =
+      PDH_status0_channel_0_current_decode(statusFrame0.channel_0_current);
+  currents[1] =
+      PDH_status0_channel_1_current_decode(statusFrame0.channel_1_current);
+  currents[2] =
+      PDH_status0_channel_2_current_decode(statusFrame0.channel_2_current);
+  currents[3] =
+      PDH_status0_channel_3_current_decode(statusFrame0.channel_3_current);
+  currents[4] =
+      PDH_status0_channel_4_current_decode(statusFrame0.channel_4_current);
+  currents[5] =
+      PDH_status0_channel_5_current_decode(statusFrame0.channel_5_current);
+  currents[6] =
+      PDH_status1_channel_6_current_decode(statusFrame1.channel_6_current);
+  currents[7] =
+      PDH_status1_channel_7_current_decode(statusFrame1.channel_7_current);
+  currents[8] =
+      PDH_status1_channel_8_current_decode(statusFrame1.channel_8_current);
+  currents[9] =
+      PDH_status1_channel_9_current_decode(statusFrame1.channel_9_current);
+  currents[10] =
+      PDH_status1_channel_10_current_decode(statusFrame1.channel_10_current);
+  currents[11] =
+      PDH_status1_channel_11_current_decode(statusFrame1.channel_11_current);
+  currents[12] =
+      PDH_status2_channel_12_current_decode(statusFrame2.channel_12_current);
+  currents[13] =
+      PDH_status2_channel_13_current_decode(statusFrame2.channel_13_current);
+  currents[14] =
+      PDH_status2_channel_14_current_decode(statusFrame2.channel_14_current);
+  currents[15] =
+      PDH_status2_channel_15_current_decode(statusFrame2.channel_15_current);
+  currents[16] =
+      PDH_status2_channel_16_current_decode(statusFrame2.channel_16_current);
+  currents[17] =
+      PDH_status2_channel_17_current_decode(statusFrame2.channel_17_current);
+  currents[18] =
+      PDH_status3_channel_18_current_decode(statusFrame3.channel_18_current);
+  currents[19] =
+      PDH_status3_channel_19_current_decode(statusFrame3.channel_19_current);
+  currents[20] =
+      PDH_status3_channel_20_current_decode(statusFrame3.channel_20_current);
+  currents[21] =
+      PDH_status3_channel_21_current_decode(statusFrame3.channel_21_current);
+  currents[22] =
+      PDH_status3_channel_22_current_decode(statusFrame3.channel_22_current);
+  currents[23] =
+      PDH_status3_channel_23_current_decode(statusFrame3.channel_23_current);
+}
+
+uint16_t HAL_REV_GetPDHTotalCurrent(HAL_REVPDHHandle handle, int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0;
+  }
+
+  return PDH_status4_total_current_decode(statusFrame.total_current);
+}
+
+void HAL_REV_SetPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
+                                     int32_t* status) {
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint8_t packedData[8] = {0};
+  PDH_switch_channel_set_t frame;
+  frame.output_set_value = enabled;
+  frame.use_system_enable = false;
+  PDH_switch_channel_set_pack(packedData, &frame, 1);
+
+  HAL_WriteCANPacket(hpdh->hcan, packedData, PDH_SWITCH_CHANNEL_SET_LENGTH,
+                     PDH_SWITCH_CHANNEL_SET_FRAME_API, status);
+}
+
+HAL_Bool HAL_REV_GetPDHSwitchableChannelState(HAL_REVPDHHandle handle,
+                                              int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_sw_state_decode(statusFrame.sw_state);
+}
+
+HAL_Bool HAL_REV_CheckPDHChannelBrownout(HAL_REVPDHHandle handle,
+                                         int32_t channel, int32_t* status) {
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  if (!HAL_REV_CheckPDHChannelNumber(channel)) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return 0;
+  }
+
+  // Determine what periodic status the channel is in
+  if (channel < 4) {
+    // Periodic status 0
+    PDH_status0_t statusFrame = HAL_REV_ReadPDHStatus0(hpdh->hcan, status);
+    switch (channel) {
+      case 0:
+        return PDH_status0_channel_0_brownout_decode(
+            statusFrame.channel_0_brownout);
+      case 1:
+        return PDH_status0_channel_1_brownout_decode(
+            statusFrame.channel_1_brownout);
+      case 2:
+        return PDH_status0_channel_2_brownout_decode(
+            statusFrame.channel_2_brownout);
+      case 3:
+        return PDH_status0_channel_3_brownout_decode(
+            statusFrame.channel_3_brownout);
+    }
+  } else if (channel < 8) {
+    // Periodic status 1
+    PDH_status1_t statusFrame = HAL_REV_ReadPDHStatus1(hpdh->hcan, status);
+    switch (channel) {
+      case 4:
+        return PDH_status1_channel_4_brownout_decode(
+            statusFrame.channel_4_brownout);
+      case 5:
+        return PDH_status1_channel_5_brownout_decode(
+            statusFrame.channel_5_brownout);
+      case 6:
+        return PDH_status1_channel_6_brownout_decode(
+            statusFrame.channel_6_brownout);
+      case 7:
+        return PDH_status1_channel_7_brownout_decode(
+            statusFrame.channel_7_brownout);
+    }
+  } else if (channel < 12) {
+    // Periodic status 2
+    PDH_status2_t statusFrame = HAL_REV_ReadPDHStatus2(hpdh->hcan, status);
+    switch (channel) {
+      case 8:
+        return PDH_status2_channel_8_brownout_decode(
+            statusFrame.channel_8_brownout);
+      case 9:
+        return PDH_status2_channel_9_brownout_decode(
+            statusFrame.channel_9_brownout);
+      case 10:
+        return PDH_status2_channel_10_brownout_decode(
+            statusFrame.channel_10_brownout);
+      case 11:
+        return PDH_status2_channel_11_brownout_decode(
+            statusFrame.channel_11_brownout);
+    }
+  } else if (channel < 24) {
+    // Periodic status 3
+    PDH_status3_t statusFrame = HAL_REV_ReadPDHStatus3(hpdh->hcan, status);
+    switch (channel) {
+      case 12:
+        return PDH_status3_channel_12_brownout_decode(
+            statusFrame.channel_12_brownout);
+      case 13:
+        return PDH_status3_channel_13_brownout_decode(
+            statusFrame.channel_13_brownout);
+      case 14:
+        return PDH_status3_channel_14_brownout_decode(
+            statusFrame.channel_14_brownout);
+      case 15:
+        return PDH_status3_channel_15_brownout_decode(
+            statusFrame.channel_15_brownout);
+      case 16:
+        return PDH_status3_channel_16_brownout_decode(
+            statusFrame.channel_16_brownout);
+      case 17:
+        return PDH_status3_channel_17_brownout_decode(
+            statusFrame.channel_17_brownout);
+      case 18:
+        return PDH_status3_channel_18_brownout_decode(
+            statusFrame.channel_18_brownout);
+      case 19:
+        return PDH_status3_channel_19_brownout_decode(
+            statusFrame.channel_19_brownout);
+      case 20:
+        return PDH_status3_channel_20_brownout_decode(
+            statusFrame.channel_20_brownout);
+      case 21:
+        return PDH_status3_channel_21_brownout_decode(
+            statusFrame.channel_21_brownout);
+      case 22:
+        return PDH_status3_channel_22_brownout_decode(
+            statusFrame.channel_22_brownout);
+      case 23:
+        return PDH_status3_channel_23_brownout_decode(
+            statusFrame.channel_23_brownout);
+    }
+  }
+  return 0;
+}
+
+double HAL_REV_GetPDHSupplyVoltage(HAL_REVPDHHandle handle, int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_v_bus_decode(statusFrame.v_bus);
+}
+
+HAL_Bool HAL_REV_IsPDHEnabled(HAL_REVPDHHandle handle, int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return false;
+  }
+
+  return PDH_status4_system_enable_decode(statusFrame.system_enable);
+}
+
+HAL_Bool HAL_REV_CheckPDHBrownout(HAL_REVPDHHandle handle, int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return false;
+  }
+
+  return PDH_status4_brownout_decode(statusFrame.brownout);
+}
+
+HAL_Bool HAL_REV_CheckPDHCANWarning(HAL_REVPDHHandle handle, int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_can_warning_decode(statusFrame.can_warning);
+}
+
+HAL_Bool HAL_REV_CheckPDHHardwareFault(HAL_REVPDHHandle handle,
+                                       int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_hardware_fault_decode(statusFrame.hardware_fault);
+}
+
+HAL_Bool HAL_REV_CheckPDHStickyBrownout(HAL_REVPDHHandle handle,
+                                        int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_sticky_brownout_decode(statusFrame.sticky_brownout);
+}
+
+HAL_Bool HAL_REV_CheckPDHStickyCANWarning(HAL_REVPDHHandle handle,
+                                          int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_sticky_can_warning_decode(statusFrame.sticky_can_warning);
+}
+
+HAL_Bool HAL_REV_CheckPDHStickyCANBusOff(HAL_REVPDHHandle handle,
+                                         int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_sticky_can_bus_off_decode(statusFrame.sticky_can_bus_off);
+}
+
+HAL_Bool HAL_REV_CheckPDHStickyHardwareFault(HAL_REVPDHHandle handle,
+                                             int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_sticky_hardware_fault_decode(
+      statusFrame.sticky_hardware_fault);
+}
+
+HAL_Bool HAL_REV_CheckPDHStickyFirmwareFault(HAL_REVPDHHandle handle,
+                                             int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_sticky_firmware_fault_decode(
+      statusFrame.sticky_firmware_fault);
+}
+
+HAL_Bool HAL_REV_CheckPDHStickyChannelBrownout(HAL_REVPDHHandle handle,
+                                               int32_t channel,
+                                               int32_t* status) {
+  if (channel < 20 || channel > 23) {
+    *status = RESOURCE_OUT_OF_RANGE;
+    return 0.0;
+  }
+
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  switch (channel) {
+    case 20:
+      return PDH_status4_sticky_ch20_brownout_decode(
+          statusFrame.sticky_ch20_brownout);
+    case 21:
+      return PDH_status4_sticky_ch21_brownout_decode(
+          statusFrame.sticky_ch21_brownout);
+    case 22:
+      return PDH_status4_sticky_ch22_brownout_decode(
+          statusFrame.sticky_ch22_brownout);
+    case 23:
+      return PDH_status4_sticky_ch23_brownout_decode(
+          statusFrame.sticky_ch23_brownout);
+  }
+  return 0;
+}
+
+HAL_Bool HAL_REV_CheckPDHStickyHasReset(HAL_REVPDHHandle handle,
+                                        int32_t* status) {
+  PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
+
+  if (*status != 0) {
+    return 0.0;
+  }
+
+  return PDH_status4_sticky_has_reset_decode(statusFrame.sticky_has_reset);
+}
+
+REV_PDH_Version HAL_REV_GetPDHVersion(HAL_REVPDHHandle handle,
+                                      int32_t* status) {
+  REV_PDH_Version version;
+  std::memset(&version, 0, sizeof(version));
+  uint8_t packedData[8] = {0};
+  int32_t length = 0;
+  uint64_t timestamp = 0;
+  PDH_version_t result = {};
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return version;
+  }
+
+  HAL_WriteCANRTRFrame(hpdh->hcan, PDH_VERSION_LENGTH, PDH_VERSION_FRAME_API,
+                       status);
+
+  if (*status != 0) {
+    return version;
+  }
+
+  HAL_ReadCANPacketTimeout(hpdh->hcan, PDH_VERSION_FRAME_API, packedData,
+                           &length, &timestamp, kDefaultControlPeriod * 2,
+                           status);
+
+  if (*status != 0) {
+    return version;
+  }
+
+  PDH_version_unpack(&result, packedData, PDH_VERSION_LENGTH);
+
+  version.firmwareMajor = result.firmware_year;
+  version.firmwareMinor = result.firmware_minor;
+  version.firmwareFix = result.firmware_fix;
+  version.hardwareRev = result.hardware_code;
+  version.uniqueId = result.unique_id;
+
+  return version;
+}
+
+void HAL_REV_ClearPDHFaults(HAL_REVPDHHandle handle, int32_t* status) {
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint8_t packedData[8] = {0};
+  HAL_WriteCANPacket(hpdh->hcan, packedData, PDH_CLEAR_FAULTS_LENGTH,
+                     PDH_CLEAR_FAULTS_FRAME_API, status);
+}
+
+void HAL_REV_IdentifyPDH(HAL_REVPDHHandle handle, int32_t* status) {
+  auto hpdh = REVPDHHandles->Get(handle);
+  if (hpdh == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  uint8_t packedData[8] = {0};
+  HAL_WriteCANPacket(hpdh->hcan, packedData, PDH_IDENTIFY_LENGTH,
+                     PDH_IDENTIFY_FRAME_API, status);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/athena/REVPDH.h b/hal/src/main/native/athena/REVPDH.h
new file mode 100644
index 0000000..228d05c
--- /dev/null
+++ b/hal/src/main/native/athena/REVPDH.h
@@ -0,0 +1,314 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_rev_pdh REV Power Distribution Hub API Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+struct REV_PDH_Version {
+  uint32_t firmwareMajor;
+  uint32_t firmwareMinor;
+  uint32_t firmwareFix;
+  uint32_t hardwareRev;
+  uint32_t uniqueId;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a REV Power Distribution Hub (PDH) device.
+ *
+ * @param module       the device CAN ID (1 .. 63)
+ * @return the created PDH handle
+ */
+HAL_REVPDHHandle HAL_REV_InitializePDH(int32_t module,
+                                       const char* allocationLocation,
+                                       int32_t* status);
+
+/**
+ * Frees a PDH device handle.
+ *
+ * @param handle        the previously created PDH handle
+ */
+void HAL_REV_FreePDH(HAL_REVPDHHandle handle);
+
+/**
+ * Gets the module number for a pdh.
+ */
+int32_t HAL_REV_GetPDHModuleNumber(HAL_REVPDHHandle handle, int32_t* status);
+
+/**
+ * Checks if a PDH module number is valid.
+ *
+ * Does not check if a PDH device with this module has been initialized.
+ *
+ * @param module        module number (1 .. 63)
+ * @return 1 if the module number is valid; 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHModuleNumber(int32_t module);
+
+/**
+ * Checks if a PDH channel number is valid.
+ *
+ * @param module        channel number (0 .. HAL_REV_PDH_NUM_CHANNELS)
+ * @return 1 if the channel number is valid; 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHChannelNumber(int32_t channel);
+
+/**
+ * Gets the current of a PDH channel in Amps.
+ *
+ * @param handle        PDH handle
+ * @param channel       the channel to retrieve the current of (0 ..
+ * HAL_REV_PDH_NUM_CHANNELS)
+ *
+ * @return the current of the PDH channel in Amps
+ */
+double HAL_REV_GetPDHChannelCurrent(HAL_REVPDHHandle handle, int32_t channel,
+                                    int32_t* status);
+
+/**
+ * @param handle        PDH handle
+ * @param currents      array of currents
+ */
+void HAL_REV_GetPDHAllChannelCurrents(HAL_REVPDHHandle handle, double* currents,
+                                      int32_t* status);
+
+/**
+ * Gets the total current of the PDH in Amps, measured to the nearest even
+ * integer.
+ *
+ * @param handle        PDH handle
+ *
+ * @return the total current of the PDH in Amps
+ */
+uint16_t HAL_REV_GetPDHTotalCurrent(HAL_REVPDHHandle handle, int32_t* status);
+
+/**
+ * Sets the state of the switchable channel on a PDH device.
+ *
+ * @param handle        PDH handle
+ * @param enabled       1 if the switchable channel should be enabled; 0
+ * otherwise
+ */
+void HAL_REV_SetPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
+                                     int32_t* status);
+
+/**
+ * Gets the current state of the switchable channel on a PDH device.
+ *
+ * This call relies on a periodic status sent by the PDH device and will be as
+ * fresh as the last packet received.
+ *
+ * @param handle        PDH handle
+ * @return 1 if the switchable channel is enabled; 0 otherwise
+ */
+HAL_Bool HAL_REV_GetPDHSwitchableChannelState(HAL_REVPDHHandle handle,
+                                              int32_t* status);
+
+/**
+ * Checks if a PDH channel is currently experiencing a brownout condition.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ * @param channel       the channel to retrieve the brownout status of
+ *
+ * @return 1 if the channel is experiencing a brownout; 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHChannelBrownout(HAL_REVPDHHandle handle,
+                                         int32_t channel, int32_t* status);
+
+/**
+ * Gets the voltage being supplied to a PDH device.
+ *
+ * @param handle        PDH handle
+ *
+ * @return the voltage at the input of the PDH in Volts
+ */
+double HAL_REV_GetPDHSupplyVoltage(HAL_REVPDHHandle handle, int32_t* status);
+
+/**
+ * Checks if a PDH device is currently enabled.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the PDH is enabled; 0 otherwise
+ */
+HAL_Bool HAL_REV_IsPDHEnabled(HAL_REVPDHHandle handle, int32_t* status);
+
+/**
+ * Checks if the input voltage on a PDH device is currently below the minimum
+ * voltage.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the PDH is experiencing a brownout; 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHBrownout(HAL_REVPDHHandle handle, int32_t* status);
+
+/**
+ * Checks if the CAN RX or TX error levels on a PDH device have exceeded the
+ * warning threshold.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the device has exceeded the warning threshold; 0
+ * otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHCANWarning(HAL_REVPDHHandle handle, int32_t* status);
+
+/**
+ * Checks if a PDH device is currently malfunctioning.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the device is in a hardware fault state; 0
+ * otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHHardwareFault(HAL_REVPDHHandle handle,
+                                       int32_t* status);
+
+/**
+ * Checks if the input voltage on a PDH device has gone below the specified
+ * minimum voltage.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the device has had a brownout; 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHStickyBrownout(HAL_REVPDHHandle handle,
+                                        int32_t* status);
+
+/**
+ * Checks if the CAN RX or TX error levels on a PDH device have exceeded the
+ * warning threshold.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the device has exceeded the CAN warning threshold;
+ * 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHStickyCANWarning(HAL_REVPDHHandle handle,
+                                          int32_t* status);
+
+/**
+ * Checks if the CAN bus on a PDH device has previously experienced a 'Bus Off'
+ * event.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the device has experienced a 'Bus Off' event; 0
+ * otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHStickyCANBusOff(HAL_REVPDHHandle handle,
+                                         int32_t* status);
+
+/**
+ * Checks if a PDH device has malfunctioned.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the device has had a malfunction; 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHStickyHardwareFault(HAL_REVPDHHandle handle,
+                                             int32_t* status);
+
+/**
+ * Checks if the firmware on a PDH device has malfunctioned and reset during
+ * operation.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the device has had a malfunction and reset; 0
+ * otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHStickyFirmwareFault(HAL_REVPDHHandle handle,
+                                             int32_t* status);
+
+/**
+ * Checks if a brownout has happened on channels 20-23 of a PDH device while it
+ * was enabled.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ * @param channel       PDH channel to retrieve sticky brownout status (20 ..
+ * 23)
+ *
+ *
+ * @return 1 if the channel has had a brownout; 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHStickyChannelBrownout(HAL_REVPDHHandle handle,
+                                               int32_t channel,
+                                               int32_t* status);
+
+/**
+ * Checks if a PDH device has reset.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ *
+ * @return 1 if the device has reset; 0 otherwise
+ */
+HAL_Bool HAL_REV_CheckPDHStickyHasReset(HAL_REVPDHHandle handle,
+                                        int32_t* status);
+
+/**
+ * Gets the firmware and hardware versions of a PDH device.
+ *
+ * @param handle        PDH handle
+ *
+ * @return version information
+ */
+REV_PDH_Version HAL_REV_GetPDHVersion(HAL_REVPDHHandle handle, int32_t* status);
+
+/**
+ * Clears the sticky faults on a PDH device.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ */
+void HAL_REV_ClearPDHFaults(HAL_REVPDHHandle handle, int32_t* status);
+
+/**
+ * Identifies a PDH device by blinking its LED.
+ *
+ * NOTE: Not implemented in firmware as of 2021-04-23.
+ *
+ * @param handle        PDH handle
+ */
+void HAL_REV_IdentifyPDH(HAL_REVPDHHandle handle, int32_t* status);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/hal/src/main/native/athena/REVPH.cpp b/hal/src/main/native/athena/REVPH.cpp
new file mode 100644
index 0000000..155f92c
--- /dev/null
+++ b/hal/src/main/native/athena/REVPH.cpp
@@ -0,0 +1,480 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <fmt/format.h>
+
+#include "HALInitializer.h"
+#include "HALInternal.h"
+#include "PortsInternal.h"
+#include "hal/CANAPI.h"
+#include "hal/Errors.h"
+#include "hal/handles/IndexedHandleResource.h"
+#include "rev/PHFrames.h"
+
+using namespace hal;
+
+static constexpr HAL_CANManufacturer manufacturer =
+    HAL_CANManufacturer::HAL_CAN_Man_kREV;
+
+static constexpr HAL_CANDeviceType deviceType =
+    HAL_CANDeviceType::HAL_CAN_Dev_kPneumatics;
+
+static constexpr int32_t kDefaultControlPeriod = 20;
+// static constexpr uint8_t kDefaultSensorMask = (1 <<
+// HAL_REV_PHSENSOR_DIGITAL);
+static constexpr uint8_t kDefaultCompressorDuty = 255;
+static constexpr uint8_t kDefaultPressureTarget = 120;
+static constexpr uint8_t kDefaultPressureHysteresis = 60;
+
+#define HAL_REV_MAX_PULSE_TIME 65534
+#define HAL_REV_MAX_PRESSURE_TARGET 120
+#define HAL_REV_MAX_PRESSURE_HYSTERESIS HAL_REV_MAX_PRESSURE_TARGET
+
+static constexpr uint32_t APIFromExtId(uint32_t extId) {
+  return (extId >> 6) & 0x3FF;
+}
+
+static constexpr uint32_t PH_SET_ALL_FRAME_API =
+    APIFromExtId(PH_SET_ALL_FRAME_ID);
+static constexpr uint32_t PH_PULSE_ONCE_FRAME_API =
+    APIFromExtId(PH_PULSE_ONCE_FRAME_ID);
+static constexpr uint32_t PH_STATUS0_FRAME_API =
+    APIFromExtId(PH_STATUS0_FRAME_ID);
+static constexpr uint32_t PH_STATUS1_FRAME_API =
+    APIFromExtId(PH_STATUS1_FRAME_ID);
+
+static constexpr int32_t kPHFrameStatus0Timeout = 50;
+static constexpr int32_t kPHFrameStatus1Timeout = 50;
+
+namespace {
+
+struct REV_PHObj {
+  int32_t controlPeriod;
+  PH_set_all_t desiredSolenoidsState;
+  wpi::mutex solenoidLock;
+  HAL_CANHandle hcan;
+  std::string previousAllocation;
+};
+
+}  // namespace
+
+static IndexedHandleResource<HAL_REVPHHandle, REV_PHObj, 63,
+                             HAL_HandleEnum::REVPH>* REVPHHandles;
+
+namespace hal::init {
+void InitializeREVPH() {
+  static IndexedHandleResource<HAL_REVPHHandle, REV_PHObj, kNumREVPHModules,
+                               HAL_HandleEnum::REVPH>
+      rH;
+  REVPHHandles = &rH;
+}
+}  // namespace hal::init
+
+static PH_status0_t HAL_REV_ReadPHStatus0(HAL_CANHandle hcan, int32_t* status) {
+  uint8_t packedData[8] = {0};
+  int32_t length = 0;
+  uint64_t timestamp = 0;
+  PH_status0_t result = {};
+
+  HAL_ReadCANPacketTimeout(hcan, PH_STATUS0_FRAME_API, packedData, &length,
+                           &timestamp, kPHFrameStatus0Timeout * 2, status);
+
+  if (*status != 0) {
+    return result;
+  }
+
+  PH_status0_unpack(&result, packedData, PH_STATUS0_LENGTH);
+
+  return result;
+}
+
+static PH_status1_t HAL_REV_ReadPHStatus1(HAL_CANHandle hcan, int32_t* status) {
+  uint8_t packedData[8] = {0};
+  int32_t length = 0;
+  uint64_t timestamp = 0;
+  PH_status1_t result = {};
+
+  HAL_ReadCANPacketTimeout(hcan, PH_STATUS1_FRAME_API, packedData, &length,
+                           &timestamp, kPHFrameStatus1Timeout * 2, status);
+
+  if (*status != 0) {
+    return result;
+  }
+
+  PH_status1_unpack(&result, packedData, PH_STATUS1_LENGTH);
+
+  return result;
+}
+
+enum REV_SolenoidState {
+  kSolenoidDisabled = 0,
+  kSolenoidEnabled,
+  kSolenoidControlledViaPulse
+};
+
+static void HAL_REV_UpdateDesiredPHSolenoidState(REV_PHObj* hph,
+                                                 int32_t solenoid,
+                                                 REV_SolenoidState state) {
+  switch (solenoid) {
+    case 0:
+      hph->desiredSolenoidsState.channel_0 = state;
+      break;
+    case 1:
+      hph->desiredSolenoidsState.channel_1 = state;
+      break;
+    case 2:
+      hph->desiredSolenoidsState.channel_2 = state;
+      break;
+    case 3:
+      hph->desiredSolenoidsState.channel_3 = state;
+      break;
+    case 4:
+      hph->desiredSolenoidsState.channel_4 = state;
+      break;
+    case 5:
+      hph->desiredSolenoidsState.channel_5 = state;
+      break;
+    case 6:
+      hph->desiredSolenoidsState.channel_6 = state;
+      break;
+    case 7:
+      hph->desiredSolenoidsState.channel_7 = state;
+      break;
+    case 8:
+      hph->desiredSolenoidsState.channel_8 = state;
+      break;
+    case 9:
+      hph->desiredSolenoidsState.channel_9 = state;
+      break;
+    case 10:
+      hph->desiredSolenoidsState.channel_10 = state;
+      break;
+    case 11:
+      hph->desiredSolenoidsState.channel_11 = state;
+      break;
+    case 12:
+      hph->desiredSolenoidsState.channel_12 = state;
+      break;
+    case 13:
+      hph->desiredSolenoidsState.channel_13 = state;
+      break;
+    case 14:
+      hph->desiredSolenoidsState.channel_14 = state;
+      break;
+    case 15:
+      hph->desiredSolenoidsState.channel_15 = state;
+      break;
+  }
+}
+
+static void HAL_REV_SendSolenoidsState(REV_PHObj* hph, int32_t* status) {
+  uint8_t packedData[PH_SET_ALL_LENGTH] = {0};
+  PH_set_all_pack(packedData, &(hph->desiredSolenoidsState), PH_SET_ALL_LENGTH);
+  HAL_WriteCANPacketRepeating(hph->hcan, packedData, PH_SET_ALL_LENGTH,
+                              PH_SET_ALL_FRAME_API, hph->controlPeriod, status);
+}
+
+static HAL_Bool HAL_REV_CheckPHPulseTime(int32_t time) {
+  return ((time > 0) && (time <= HAL_REV_MAX_PULSE_TIME)) ? 1 : 0;
+}
+
+HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
+                                    const char* allocationLocation,
+                                    int32_t* status) {
+  hal::init::CheckInit();
+  if (!HAL_CheckREVPHModuleNumber(module)) {
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
+                                     kNumREVPHModules, module);
+    return HAL_kInvalidHandle;
+  }
+
+  HAL_REVPHHandle handle;
+  auto hph = REVPHHandles->Allocate(module, &handle, status);
+  if (*status != 0) {
+    if (hph) {
+      hal::SetLastErrorPreviouslyAllocated(status, "REV PH", module,
+                                           hph->previousAllocation);
+    } else {
+      hal::SetLastErrorIndexOutOfRange(status, "Invalid Index for REV PH", 1,
+                                       kNumREVPHModules, module);
+    }
+    return HAL_kInvalidHandle;  // failed to allocate. Pass error back.
+  }
+
+  HAL_CANHandle hcan =
+      HAL_InitializeCAN(manufacturer, module, deviceType, status);
+
+  if (*status != 0) {
+    REVPHHandles->Free(handle);
+    return HAL_kInvalidHandle;
+  }
+
+  hph->previousAllocation = allocationLocation ? allocationLocation : "";
+  hph->hcan = hcan;
+  hph->controlPeriod = kDefaultControlPeriod;
+
+  // Start closed-loop compressor control by starting solenoid state updates
+  HAL_REV_SendSolenoidsState(hph.get(), status);
+
+  return handle;
+}
+
+void HAL_FreeREVPH(HAL_REVPHHandle handle) {
+  auto hph = REVPHHandles->Get(handle);
+  if (hph == nullptr)
+    return;
+
+  HAL_CleanCAN(hph->hcan);
+
+  REVPHHandles->Free(handle);
+}
+
+HAL_Bool HAL_CheckREVPHModuleNumber(int32_t module) {
+  return module >= 1 && module < kNumREVPDHModules;
+}
+
+HAL_Bool HAL_CheckREVPHSolenoidChannel(int32_t channel) {
+  return channel >= 0 && channel < kNumREVPHChannels;
+}
+
+HAL_Bool HAL_GetREVPHCompressor(HAL_REVPHHandle handle, int32_t* status) {
+  auto ph = REVPHHandles->Get(handle);
+  if (ph == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
+
+  if (*status != 0) {
+    return false;
+  }
+
+  return status0.compressor_on;
+}
+
+void HAL_SetREVPHClosedLoopControl(HAL_REVPHHandle handle, HAL_Bool enabled,
+                                   int32_t* status) {
+  // TODO
+}
+
+HAL_Bool HAL_GetREVPHClosedLoopControl(HAL_REVPHHandle handle,
+                                       int32_t* status) {
+  return false;  // TODO
+}
+
+HAL_Bool HAL_GetREVPHPressureSwitch(HAL_REVPHHandle handle, int32_t* status) {
+  auto ph = REVPHHandles->Get(handle);
+  if (ph == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return false;
+  }
+
+  PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
+
+  if (*status != 0) {
+    return false;
+  }
+
+  return status0.digital_sensor;
+}
+
+double HAL_GetREVPHCompressorCurrent(HAL_REVPHHandle handle, int32_t* status) {
+  auto ph = REVPHHandles->Get(handle);
+  if (ph == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  PH_status1_t status1 = HAL_REV_ReadPHStatus1(ph->hcan, status);
+
+  if (*status != 0) {
+    return 0;
+  }
+
+  return PH_status1_compressor_current_decode(status1.compressor_current);
+}
+
+double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
+                                  int32_t* status) {
+  auto ph = REVPHHandles->Get(handle);
+  if (ph == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  if (channel < 0 || channel > 1) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastErrorIndexOutOfRange(status, "Invalid REV Analog Index", 0, 2,
+                                     channel);
+    return 0;
+  }
+
+  PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
+
+  if (*status != 0) {
+    return 0;
+  }
+
+  if (channel == 1) {
+    return PH_status0_analog_0_decode(status0.analog_0);
+  }
+  return PH_status0_analog_1_decode(status0.analog_1);
+}
+
+int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status) {
+  auto ph = REVPHHandles->Get(handle);
+  if (ph == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return 0;
+  }
+
+  PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
+
+  if (*status != 0) {
+    return 0;
+  }
+
+  uint32_t result = status0.channel_0;
+  result |= status0.channel_1 << 1;
+  result |= status0.channel_2 << 2;
+  result |= status0.channel_3 << 3;
+  result |= status0.channel_4 << 4;
+  result |= status0.channel_5 << 5;
+  result |= status0.channel_6 << 6;
+  result |= status0.channel_7 << 7;
+  result |= status0.channel_8 << 8;
+  result |= status0.channel_9 << 9;
+  result |= status0.channel_10 << 10;
+  result |= status0.channel_11 << 11;
+  result |= status0.channel_12 << 12;
+  result |= status0.channel_13 << 13;
+  result |= status0.channel_14 << 14;
+  result |= status0.channel_15 << 15;
+
+  return result;
+}
+
+void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
+                           int32_t* status) {
+  auto ph = REVPHHandles->Get(handle);
+  if (ph == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  std::scoped_lock lock{ph->solenoidLock};
+  for (int solenoid = 0; solenoid < kNumREVPHChannels; solenoid++) {
+    if (mask & (1 << solenoid)) {
+      // The mask bit for the solenoid is set, so we update the solenoid state
+      REV_SolenoidState desiredSolenoidState =
+          values & (1 << solenoid) ? kSolenoidEnabled : kSolenoidDisabled;
+      HAL_REV_UpdateDesiredPHSolenoidState(ph.get(), solenoid,
+                                           desiredSolenoidState);
+    }
+  }
+  HAL_REV_SendSolenoidsState(ph.get(), status);
+}
+
+void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
+                          int32_t* status) {
+  auto ph = REVPHHandles->Get(handle);
+  if (ph == nullptr) {
+    *status = HAL_HANDLE_ERROR;
+    return;
+  }
+
+  if (index >= kNumREVPHChannels || index < 0) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Only [0-15] are valid index values. Requested {}", index));
+    return;
+  }
+
+  if (!HAL_REV_CheckPHPulseTime(durMs)) {
+    *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Time not within expected range [0-65534]. Requested {}",
+                    durMs));
+    return;
+  }
+
+  {
+    std::scoped_lock lock{ph->solenoidLock};
+    HAL_REV_UpdateDesiredPHSolenoidState(ph.get(), index,
+                                         kSolenoidControlledViaPulse);
+    HAL_REV_SendSolenoidsState(ph.get(), status);
+  }
+
+  if (*status != 0) {
+    return;
+  }
+
+  PH_pulse_once_t pulse = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+  pulse.pulse_length_ms = durMs;
+
+  // Specify which solenoid should be pulsed
+  // The protocol supports specifying any number of solenoids to be pulsed at
+  // the same time, should that functionality be exposed to users in the future.
+  switch (index) {
+    case 0:
+      pulse.channel_0 = true;
+      break;
+    case 1:
+      pulse.channel_1 = true;
+      break;
+    case 2:
+      pulse.channel_2 = true;
+      break;
+    case 3:
+      pulse.channel_3 = true;
+      break;
+    case 4:
+      pulse.channel_4 = true;
+      break;
+    case 5:
+      pulse.channel_5 = true;
+      break;
+    case 6:
+      pulse.channel_6 = true;
+      break;
+    case 7:
+      pulse.channel_7 = true;
+      break;
+    case 8:
+      pulse.channel_8 = true;
+      break;
+    case 9:
+      pulse.channel_9 = true;
+      break;
+    case 10:
+      pulse.channel_10 = true;
+      break;
+    case 11:
+      pulse.channel_11 = true;
+      break;
+    case 12:
+      pulse.channel_12 = true;
+      break;
+    case 13:
+      pulse.channel_13 = true;
+      break;
+    case 14:
+      pulse.channel_14 = true;
+      break;
+    case 15:
+      pulse.channel_15 = true;
+      break;
+  }
+
+  // Send pulse command
+  uint8_t packedData[PH_PULSE_ONCE_LENGTH] = {0};
+  PH_pulse_once_pack(packedData, &pulse, PH_PULSE_ONCE_LENGTH);
+  HAL_WriteCANPacket(ph->hcan, packedData, PH_PULSE_ONCE_LENGTH,
+                     PH_PULSE_ONCE_FRAME_API, status);
+}
diff --git a/hal/src/main/native/athena/Relay.cpp b/hal/src/main/native/athena/Relay.cpp
index 4dffa36..a01dd9d 100644
--- a/hal/src/main/native/athena/Relay.cpp
+++ b/hal/src/main/native/athena/Relay.cpp
@@ -1,14 +1,14 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "hal/Relay.h"
 
+#include <string>
+
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "PortsInternal.h"
 #include "hal/handles/IndexedHandleResource.h"
 
@@ -19,6 +19,7 @@
 struct Relay {
   uint8_t channel;
   bool fwd;
+  std::string previousAllocation;
 };
 
 }  // namespace
@@ -29,46 +30,54 @@
 // Create a mutex to protect changes to the relay values
 static wpi::mutex digitalRelayMutex;
 
-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();
   initializeDigital(status);
 
-  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;
 
@@ -78,6 +87,7 @@
   }
 
   port->channel = static_cast<uint8_t>(channel);
+  port->previousAllocation = allocationLocation ? allocationLocation : "";
   return handle;
 }
 
@@ -108,7 +118,9 @@
     relays = relaySystem->readValue_Reverse(status);
   }
 
-  if (*status != 0) return;  // bad status read
+  if (*status != 0) {
+    return;  // bad status read
+  }
 
   if (on) {
     relays |= 1 << port->channel;
diff --git a/hal/src/main/native/athena/SPI.cpp b/hal/src/main/native/athena/SPI.cpp
index 37c5f0e..1121fd8 100644
--- a/hal/src/main/native/athena/SPI.cpp
+++ b/hal/src/main/native/athena/SPI.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/SPI.h"
 
@@ -14,13 +11,15 @@
 
 #include <array>
 #include <atomic>
+#include <cstdio>
 #include <cstring>
 
+#include <fmt/format.h>
 #include <wpi/mutex.h>
-#include <wpi/raw_ostream.h>
 
 #include "DigitalInternal.h"
 #include "HALInitializer.h"
+#include "HALInternal.h"
 #include "hal/DIO.h"
 #include "hal/HAL.h"
 #include "hal/handles/HandlesInternal.h"
@@ -54,17 +53,17 @@
   // SPI engine conflicts with any other chip selects on the same SPI device.
   // There are two SPI devices: one for ports 0-3 (onboard), the other for port
   // 4 (MXP).
-  if (!spiAutoRunning) return false;
+  if (!spiAutoRunning) {
+    return false;
+  }
   std::scoped_lock lock(spiAutoMutex);
   return (spiAutoPort >= 0 && spiAutoPort <= 3 && port >= 0 && port <= 3) ||
          (spiAutoPort == 4 && port == 4);
 }
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeSPI() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -73,19 +72,21 @@
   if (spiPortCount.fetch_add(1) == 0) {
     // Have not been initialized yet
     initializeDigital(status);
-    if (*status != 0) return;
+    if (*status != 0) {
+      return;
+    }
     // MISO
     if ((digitalHandles[3] = HAL_InitializeDIOPort(createPortHandleForSPI(29),
-                                                   false, status)) ==
+                                                   false, nullptr, status)) ==
         HAL_kInvalidHandle) {
-      std::printf("Failed to allocate DIO 29 (MISO)\n");
+      std::puts("Failed to allocate DIO 29 (MISO)");
       return;
     }
     // MOSI
     if ((digitalHandles[4] = HAL_InitializeDIOPort(createPortHandleForSPI(30),
-                                                   false, status)) ==
+                                                   false, nullptr, status)) ==
         HAL_kInvalidHandle) {
-      std::printf("Failed to allocate DIO 30 (MOSI)\n");
+      std::puts("Failed to allocate DIO 30 (MOSI)");
       HAL_FreeDIOPort(digitalHandles[3]);  // free the first port allocated
       return;
     }
@@ -104,20 +105,28 @@
   hal::init::CheckInit();
   if (port < 0 || port >= kSpiMaxHandles) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Serial port must be between 0 and {}. Requested {}",
+                    kSpiMaxHandles, static_cast<int>(port)));
     return;
   }
 
   int handle;
-  if (HAL_GetSPIHandle(port) != 0) return;
+  if (HAL_GetSPIHandle(port) != 0) {
+    return;
+  }
   switch (port) {
     case HAL_SPI_kOnboardCS0:
       CommonSPIPortInit(status);
-      if (*status != 0) return;
+      if (*status != 0) {
+        return;
+      }
       // CS0 is not a DIO port, so nothing to allocate
       handle = open("/dev/spidev0.0", O_RDWR);
       if (handle < 0) {
-        std::printf("Failed to open SPI port %d: %s\n", port,
-                    std::strerror(errno));
+        fmt::print("Failed to open SPI port {}: {}\n", port,
+                   std::strerror(errno));
         CommonSPIPortFree();
         return;
       }
@@ -125,19 +134,21 @@
       break;
     case HAL_SPI_kOnboardCS1:
       CommonSPIPortInit(status);
-      if (*status != 0) return;
+      if (*status != 0) {
+        return;
+      }
       // CS1, Allocate
       if ((digitalHandles[0] = HAL_InitializeDIOPort(createPortHandleForSPI(26),
-                                                     false, status)) ==
+                                                     false, nullptr, status)) ==
           HAL_kInvalidHandle) {
-        std::printf("Failed to allocate DIO 26 (CS1)\n");
+        std::puts("Failed to allocate DIO 26 (CS1)");
         CommonSPIPortFree();
         return;
       }
       handle = open("/dev/spidev0.1", O_RDWR);
       if (handle < 0) {
-        std::printf("Failed to open SPI port %d: %s\n", port,
-                    std::strerror(errno));
+        fmt::print("Failed to open SPI port {}: {}\n", port,
+                   std::strerror(errno));
         CommonSPIPortFree();
         HAL_FreeDIOPort(digitalHandles[0]);
         return;
@@ -146,19 +157,21 @@
       break;
     case HAL_SPI_kOnboardCS2:
       CommonSPIPortInit(status);
-      if (*status != 0) return;
+      if (*status != 0) {
+        return;
+      }
       // CS2, Allocate
       if ((digitalHandles[1] = HAL_InitializeDIOPort(createPortHandleForSPI(27),
-                                                     false, status)) ==
+                                                     false, nullptr, status)) ==
           HAL_kInvalidHandle) {
-        std::printf("Failed to allocate DIO 27 (CS2)\n");
+        std::puts("Failed to allocate DIO 27 (CS2)");
         CommonSPIPortFree();
         return;
       }
       handle = open("/dev/spidev0.2", O_RDWR);
       if (handle < 0) {
-        std::printf("Failed to open SPI port %d: %s\n", port,
-                    std::strerror(errno));
+        fmt::print("Failed to open SPI port {}: {}\n", port,
+                   std::strerror(errno));
         CommonSPIPortFree();
         HAL_FreeDIOPort(digitalHandles[1]);
         return;
@@ -167,19 +180,21 @@
       break;
     case HAL_SPI_kOnboardCS3:
       CommonSPIPortInit(status);
-      if (*status != 0) return;
+      if (*status != 0) {
+        return;
+      }
       // CS3, Allocate
       if ((digitalHandles[2] = HAL_InitializeDIOPort(createPortHandleForSPI(28),
-                                                     false, status)) ==
+                                                     false, nullptr, status)) ==
           HAL_kInvalidHandle) {
-        std::printf("Failed to allocate DIO 28 (CS3)\n");
+        std::puts("Failed to allocate DIO 28 (CS3)");
         CommonSPIPortFree();
         return;
       }
       handle = open("/dev/spidev0.3", O_RDWR);
       if (handle < 0) {
-        std::printf("Failed to open SPI port %d: %s\n", port,
-                    std::strerror(errno));
+        fmt::print("Failed to open SPI port {}: {}\n", port,
+                   std::strerror(errno));
         CommonSPIPortFree();
         HAL_FreeDIOPort(digitalHandles[2]);
         return;
@@ -188,32 +203,34 @@
       break;
     case HAL_SPI_kMXP:
       initializeDigital(status);
-      if (*status != 0) return;
+      if (*status != 0) {
+        return;
+      }
       if ((digitalHandles[5] = HAL_InitializeDIOPort(createPortHandleForSPI(14),
-                                                     false, status)) ==
+                                                     false, nullptr, status)) ==
           HAL_kInvalidHandle) {
-        wpi::outs() << "Failed to allocate DIO 14\n";
+        std::puts("Failed to allocate DIO 14");
         return;
       }
       if ((digitalHandles[6] = HAL_InitializeDIOPort(createPortHandleForSPI(15),
-                                                     false, status)) ==
+                                                     false, nullptr, status)) ==
           HAL_kInvalidHandle) {
-        wpi::outs() << "Failed to allocate DIO 15\n";
+        std::puts("Failed to allocate DIO 15");
         HAL_FreeDIOPort(digitalHandles[5]);  // free the first port allocated
         return;
       }
       if ((digitalHandles[7] = HAL_InitializeDIOPort(createPortHandleForSPI(16),
-                                                     false, status)) ==
+                                                     false, nullptr, status)) ==
           HAL_kInvalidHandle) {
-        wpi::outs() << "Failed to allocate DIO 16\n";
+        std::puts("Failed to allocate DIO 16");
         HAL_FreeDIOPort(digitalHandles[5]);  // free the first port allocated
         HAL_FreeDIOPort(digitalHandles[6]);  // free the second port allocated
         return;
       }
       if ((digitalHandles[8] = HAL_InitializeDIOPort(createPortHandleForSPI(17),
-                                                     false, status)) ==
+                                                     false, nullptr, status)) ==
           HAL_kInvalidHandle) {
-        wpi::outs() << "Failed to allocate DIO 17\n";
+        std::puts("Failed to allocate DIO 17");
         HAL_FreeDIOPort(digitalHandles[5]);  // free the first port allocated
         HAL_FreeDIOPort(digitalHandles[6]);  // free the second port allocated
         HAL_FreeDIOPort(digitalHandles[7]);  // free the third port allocated
@@ -223,8 +240,8 @@
           digitalSystem->readEnableMXPSpecialFunction(status) | 0x00F0, status);
       handle = open("/dev/spidev1.0", O_RDWR);
       if (handle < 0) {
-        std::printf("Failed to open SPI port %d: %s\n", port,
-                    std::strerror(errno));
+        fmt::print("Failed to open SPI port {}: {}\n", port,
+                   std::strerror(errno));
         HAL_FreeDIOPort(digitalHandles[5]);  // free the first port allocated
         HAL_FreeDIOPort(digitalHandles[6]);  // free the second port allocated
         HAL_FreeDIOPort(digitalHandles[7]);  // free the third port allocated
@@ -235,6 +252,8 @@
       break;
     default:
       *status = PARAMETER_OUT_OF_RANGE;
+      hal::SetLastError(
+          status, fmt::format("Invalid SPI port {}", static_cast<int>(port)));
       break;
   }
 }
@@ -245,7 +264,9 @@
     return -1;
   }
 
-  if (SPIInUseByAuto(port)) return -1;
+  if (SPIInUseByAuto(port)) {
+    return -1;
+  }
 
   struct spi_ioc_transfer xfer;
   std::memset(&xfer, 0, sizeof(xfer));
@@ -263,7 +284,9 @@
     return -1;
   }
 
-  if (SPIInUseByAuto(port)) return -1;
+  if (SPIInUseByAuto(port)) {
+    return -1;
+  }
 
   struct spi_ioc_transfer xfer;
   std::memset(&xfer, 0, sizeof(xfer));
@@ -279,7 +302,9 @@
     return -1;
   }
 
-  if (SPIInUseByAuto(port)) return -1;
+  if (SPIInUseByAuto(port)) {
+    return -1;
+  }
 
   struct spi_ioc_transfer xfer;
   std::memset(&xfer, 0, sizeof(xfer));
@@ -357,6 +382,10 @@
 void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status) {
   if (port < 0 || port >= kSpiMaxHandles) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Serial port must be between 0 and {}. Requested {}",
+                    kSpiMaxHandles, static_cast<int>(port)));
     return;
   }
 
@@ -372,6 +401,10 @@
 void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status) {
   if (port < 0 || port >= kSpiMaxHandles) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Serial port must be between 0 and {}. Requested {}",
+                    kSpiMaxHandles, static_cast<int>(port)));
     return;
   }
 
@@ -436,6 +469,10 @@
 void HAL_InitSPIAuto(HAL_SPIPort port, int32_t bufferSize, int32_t* status) {
   if (port < 0 || port >= kSpiMaxHandles) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Serial port must be between 0 and {}. Requested {}",
+                    kSpiMaxHandles, static_cast<int>(port)));
     return;
   }
 
@@ -467,11 +504,17 @@
 void HAL_FreeSPIAuto(HAL_SPIPort port, int32_t* status) {
   if (port < 0 || port >= kSpiMaxHandles) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format("Serial port must be between 0 and {}. Requested {}",
+                    kSpiMaxHandles, static_cast<int>(port)));
     return;
   }
 
   std::scoped_lock lock(spiAutoMutex);
-  if (spiAutoPort != port) return;
+  if (spiAutoPort != port) {
+    return;
+  }
   spiAutoPort = kSpiMaxHandles;
 
   // disable by setting to internal clock and setting rate=0
@@ -567,11 +610,21 @@
                                 int32_t* status) {
   if (dataSize < 0 || dataSize > 32) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format(
+            "Data size must be between 0 and 32 inclusive. Requested {}",
+            dataSize));
     return;
   }
 
   if (zeroSize < 0 || zeroSize > 127) {
     *status = PARAMETER_OUT_OF_RANGE;
+    hal::SetLastError(
+        status,
+        fmt::format(
+            "Zero size must be between 0 and 127 inclusive. Requested {}",
+            zeroSize));
     return;
   }
 
diff --git a/hal/src/main/native/athena/SerialPort.cpp b/hal/src/main/native/athena/SerialPort.cpp
index 7ef9b70..374986b 100644
--- a/hal/src/main/native/athena/SerialPort.cpp
+++ b/hal/src/main/native/athena/SerialPort.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/SerialPort.h"
 
@@ -22,6 +19,9 @@
 #include <string>
 #include <thread>
 
+#include <fmt/format.h>
+
+#include "HALInternal.h"
 #include "hal/cpp/SerialHelper.h"
 #include "hal/handles/HandlesInternal.h"
 #include "hal/handles/IndexedHandleResource.h"
@@ -44,16 +44,14 @@
                       HAL_HandleEnum::SerialPort>* serialPortHandles;
 }  // namespace hal
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeSerialPort() {
   static IndexedHandleResource<HAL_SerialPortHandle, SerialPort, 4,
                                HAL_HandleEnum::SerialPort>
       spH;
   serialPortHandles = &spH;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 using namespace hal;
 
@@ -75,22 +73,20 @@
 HAL_SerialPortHandle HAL_InitializeSerialPortDirect(HAL_SerialPort port,
                                                     const char* portName,
                                                     int32_t* status) {
-  auto handle = serialPortHandles->Allocate(static_cast<int16_t>(port), status);
+  HAL_SerialPortHandle handle;
+  auto serialPort =
+      serialPortHandles->Allocate(static_cast<int16_t>(port), &handle, status);
 
   if (*status != 0) {
     return HAL_kInvalidHandle;
   }
 
-  auto serialPort = serialPortHandles->Get(handle);
-
-  if (serialPort == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return HAL_kInvalidHandle;
-  }
-
   serialPort->portId = open(portName, O_RDWR | O_NOCTTY);
   if (serialPort->portId < 0) {
     *status = errno;
+    if (*status == EACCES) {
+      *status = HAL_CONSOLE_OUT_ENABLED_ERROR;
+    }
     serialPortHandles->Free(handle);
     return HAL_kInvalidHandle;
   }
@@ -193,6 +189,7 @@
     BAUDCASE(4000000)
     default:
       *status = PARAMETER_OUT_OF_RANGE;
+      hal::SetLastError(status, fmt::format("Invalid BaudRate: {}", baud));
       return;
   }
   int err = cfsetospeed(&port->tty, static_cast<speed_t>(port->baudRate));
@@ -235,6 +232,7 @@
       break;
     default:
       *status = PARAMETER_OUT_OF_RANGE;
+      hal::SetLastError(status, fmt::format("Invalid data bits: {}", bits));
       return;
   }
 
@@ -282,6 +280,7 @@
       break;
     default:
       *status = PARAMETER_OUT_OF_RANGE;
+      hal::SetLastError(status, fmt::format("Invalid parity bits: {}", parity));
       return;
   }
 
@@ -309,6 +308,7 @@
       break;
     default:
       *status = PARAMETER_OUT_OF_RANGE;
+      hal::SetLastError(status, fmt::format("Invalid stop bits: {}", stopBits));
       return;
   }
 
@@ -344,6 +344,7 @@
       break;
     default:
       *status = PARAMETER_OUT_OF_RANGE;
+      hal::SetLastError(status, fmt::format("Invalid fc bits: {}", flow));
       return;
   }
 
@@ -417,7 +418,9 @@
 int32_t HAL_ReadSerial(HAL_SerialPortHandle handle, char* buffer, int32_t count,
                        int32_t* status) {
   // Don't do anything if 0 bytes were requested
-  if (count == 0) return 0;
+  if (count == 0) {
+    return 0;
+  }
 
   auto port = serialPortHandles->Get(handle);
   if (!port) {
diff --git a/hal/src/main/native/athena/SimDevice.cpp b/hal/src/main/native/athena/SimDevice.cpp
index 94a65d4..3a15f46 100644
--- a/hal/src/main/native/athena/SimDevice.cpp
+++ b/hal/src/main/native/athena/SimDevice.cpp
@@ -1,32 +1,38 @@
-/*----------------------------------------------------------------------------*/
-/* 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"
 
 extern "C" {
 
-HAL_SimDeviceHandle HAL_CreateSimDevice(const char* name) { return 0; }
+HAL_SimDeviceHandle HAL_CreateSimDevice(const char* name) {
+  return 0;
+}
 
 void HAL_FreeSimDevice(HAL_SimDeviceHandle handle) {}
 
 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 0;
 }
 
 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 0;
 }
 
+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 0;
+}
+
 void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) {
   value->type = HAL_UNASSIGNED;
 }
@@ -34,6 +40,8 @@
 void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value) {
 }
 
+void HAL_ResetSimValue(HAL_SimValueHandle handle) {}
+
 hal::SimDevice::SimDevice(const char* name, int index) {}
 
 hal::SimDevice::SimDevice(const char* name, int index, int channel) {}
diff --git a/hal/src/main/native/athena/Solenoid.cpp b/hal/src/main/native/athena/Solenoid.cpp
deleted file mode 100644
index ab563b3..0000000
--- a/hal/src/main/native/athena/Solenoid.cpp
+++ /dev/null
@@ -1,187 +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 "PCMInternal.h"
-#include "PortsInternal.h"
-#include "ctre/PCM.h"
-#include "hal/Errors.h"
-#include "hal/handles/HandlesInternal.h"
-#include "hal/handles/IndexedHandleResource.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;
-  }
-
-  // initializePCM will check the module
-  if (!HAL_CheckSolenoidChannel(channel)) {
-    *status = RESOURCE_OUT_OF_RANGE;
-    return HAL_kInvalidHandle;
-  }
-
-  initializePCM(module, status);
-  if (*status != 0) {
-    return HAL_kInvalidHandle;
-  }
-
-  auto handle = solenoidHandles->Allocate(
-      module * kNumSolenoidChannels + channel, status);
-  if (*status != 0) {
-    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);
-
-  return handle;
-}
-
-void HAL_FreeSolenoidPort(HAL_SolenoidHandle solenoidPortHandle) {
-  solenoidHandles->Free(solenoidPortHandle);
-}
-
-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;
-  }
-  bool value;
-
-  *status = PCM_modules[port->module]->GetSolenoid(port->channel, value);
-
-  return value;
-}
-
-int32_t HAL_GetAllSolenoids(int32_t module, int32_t* status) {
-  if (!checkPCMInit(module, status)) return 0;
-  uint8_t value;
-
-  *status = PCM_modules[module]->GetAllSolenoids(value);
-
-  return value;
-}
-
-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;
-  }
-
-  *status = PCM_modules[port->module]->SetSolenoid(port->channel, value);
-}
-
-void HAL_SetAllSolenoids(int32_t module, int32_t state, int32_t* status) {
-  if (!checkPCMInit(module, status)) return;
-
-  *status = PCM_modules[module]->SetAllSolenoids(state);
-}
-
-int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status) {
-  if (!checkPCMInit(module, status)) return 0;
-  uint8_t value;
-
-  *status = PCM_modules[module]->GetSolenoidBlackList(value);
-
-  return value;
-}
-HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status) {
-  if (!checkPCMInit(module, status)) return 0;
-  bool value;
-
-  *status = PCM_modules[module]->GetSolenoidStickyFault(value);
-
-  return value;
-}
-HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status) {
-  if (!checkPCMInit(module, status)) return false;
-  bool value;
-
-  *status = PCM_modules[module]->GetSolenoidFault(value);
-
-  return value;
-}
-void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status) {
-  if (!checkPCMInit(module, status)) return;
-
-  *status = PCM_modules[module]->ClearStickyFaults();
-}
-
-void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
-                            int32_t durMS, int32_t* status) {
-  auto port = solenoidHandles->Get(solenoidPortHandle);
-  if (port == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  *status =
-      PCM_modules[port->module]->SetOneShotDurationMs(port->channel, durMS);
-}
-
-void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status) {
-  auto port = solenoidHandles->Get(solenoidPortHandle);
-  if (port == nullptr) {
-    *status = HAL_HANDLE_ERROR;
-    return;
-  }
-
-  *status = PCM_modules[port->module]->FireOneShotSolenoid(port->channel);
-}
-}  // extern "C"
diff --git a/hal/src/main/native/athena/Threads.cpp b/hal/src/main/native/athena/Threads.cpp
index 95d1f59..aa55b56 100644
--- a/hal/src/main/native/athena/Threads.cpp
+++ b/hal/src/main/native/athena/Threads.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/Threads.h"
 
@@ -12,11 +9,9 @@
 
 #include "hal/Errors.h"
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeThreads() {}
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -37,8 +32,8 @@
     return sch.sched_priority;
   } else {
     *isRealTime = false;
-    // 0 is the only suppored priority for non-realtime, so scale to 1
-    return 1;
+    // 0 is the only supported priority for non-real-time
+    return 0;
   }
 }
 
@@ -69,11 +64,13 @@
   int policy;
   pthread_getschedparam(*reinterpret_cast<const pthread_t*>(handle), &policy,
                         &sch);
-  if (scheduler == SCHED_FIFO || scheduler == SCHED_RR)
+  if (scheduler == SCHED_FIFO || scheduler == SCHED_RR) {
     sch.sched_priority = priority;
-  else
+  } else {
     // Only need to set 0 priority for non RT thread
     sch.sched_priority = 0;
+  }
+
   if (pthread_setschedparam(*reinterpret_cast<const pthread_t*>(handle),
                             scheduler, &sch)) {
     *status = HAL_THREAD_PRIORITY_ERROR;
diff --git a/hal/src/main/native/athena/cpp/SerialHelper.cpp b/hal/src/main/native/athena/cpp/SerialHelper.cpp
index 2156147..3831769 100644
--- a/hal/src/main/native/athena/cpp/SerialHelper.cpp
+++ b/hal/src/main/native/athena/cpp/SerialHelper.cpp
@@ -1,18 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* 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/cpp/SerialHelper.h"
 
 #include <algorithm>
 #include <cstdio>
 #include <cstring>
+#include <string_view>
 
-#include <wpi/FileSystem.h>
-#include <wpi/StringRef.h>
+#include <wpi/StringExtras.h>
+#include <wpi/fs.h>
 
 #include "hal/Errors.h"
 #include "visa/visa.h"
@@ -56,7 +54,7 @@
     return "";
     // Error
   } else {
-    return m_visaResource[visaIndex].str();
+    return std::string{m_visaResource[visaIndex].str()};
   }
 }
 
@@ -83,7 +81,7 @@
     return "";
     // Error
   } else {
-    return m_osResource[osIndex].str();
+    return std::string{m_osResource[osIndex].str()};
   }
 }
 
@@ -139,8 +137,8 @@
   std::sort(m_sortedHubPath.begin(), m_sortedHubPath.end(),
             [](const wpi::SmallVectorImpl<char>& lhs,
                const wpi::SmallVectorImpl<char>& rhs) -> int {
-              wpi::StringRef lhsRef(lhs.begin(), lhs.size());
-              wpi::StringRef rhsRef(rhs.begin(), rhs.size());
+              std::string_view lhsRef(lhs.begin(), lhs.size());
+              std::string_view rhsRef(rhs.begin(), rhs.size());
               return lhsRef.compare(rhsRef);
             });
 }
@@ -150,15 +148,15 @@
   wpi::SmallVector<wpi::SmallString<16>, 4> sortedVec;
   for (auto& str : m_sortedHubPath) {
     for (size_t i = 0; i < m_unsortedHubPath.size(); i++) {
-      if (wpi::StringRef{m_unsortedHubPath[i].begin(),
-                         m_unsortedHubPath[i].size()}
-              .equals(wpi::StringRef{str.begin(), str.size()})) {
+      if (wpi::equals(std::string_view{m_unsortedHubPath[i].begin(),
+                                       m_unsortedHubPath[i].size()},
+                      std::string_view{str.begin(), str.size()})) {
         sortedVec.push_back(vec[i]);
         break;
       }
     }
   }
-  vec = sortedVec;
+  vec.swap(sortedVec);
 }
 
 void SerialHelper::QueryHubPaths(int32_t* status) {
@@ -194,73 +192,82 @@
     // Open the resource, grab its interface name, and close it.
     ViSession vSession;
     *status = viOpen(m_resourceHandle, desc, VI_NULL, VI_NULL, &vSession);
-    if (*status < 0) goto done;
+    if (*status < 0)
+      goto done;
     *status = 0;
 
     *status = viGetAttribute(vSession, VI_ATTR_INTF_INST_NAME, &osName);
     // Ignore an error here, as we want to close the session on an error
     // Use a separate close variable so we can check
     ViStatus closeStatus = viClose(vSession);
-    if (*status < 0) goto done;
-    if (closeStatus < 0) goto done;
+    if (*status < 0)
+      goto done;
+    if (closeStatus < 0)
+      goto done;
     *status = 0;
 
     // split until (/dev/
-    wpi::StringRef devNameRef = wpi::StringRef{osName}.split("(/dev/").second;
+    std::string_view devNameRef = wpi::split(osName, "(/dev/").second;
     // String not found, continue
-    if (devNameRef.equals("")) continue;
+    if (wpi::equals(devNameRef, ""))
+      continue;
 
     // Split at )
-    wpi::StringRef matchString = devNameRef.split(')').first;
-    if (matchString.equals(devNameRef)) continue;
+    std::string_view matchString = wpi::split(devNameRef, ')').first;
+    if (wpi::equals(matchString, devNameRef))
+      continue;
 
     // Search directories to get a list of system accessors
     // The directories we need are not symbolic, so we can safely
     // disable symbolic links.
     std::error_code ec;
-    for (auto p = wpi::sys::fs::recursive_directory_iterator(
-             "/sys/devices/soc0", ec, false);
-         p != wpi::sys::fs::recursive_directory_iterator(); p.increment(ec)) {
-      if (ec) break;
-      wpi::StringRef path{p->path()};
-      if (path.find("amba") == wpi::StringRef::npos) continue;
-      if (path.find("usb") == wpi::StringRef::npos) continue;
-      if (path.find(matchString) == wpi::StringRef::npos) continue;
+    for (auto& p : fs::recursive_directory_iterator("/sys/devices/soc0", ec)) {
+      if (ec)
+        break;
+      std::string path = p.path();
+      if (path.find("amba") == std::string::npos)
+        continue;
+      if (path.find("usb") == std::string::npos)
+        continue;
+      if (path.find(matchString) == std::string::npos)
+        continue;
 
-      wpi::SmallVector<wpi::StringRef, 16> pathSplitVec;
+      wpi::SmallVector<std::string_view, 16> pathSplitVec;
       // Split path into individual directories
-      path.split(pathSplitVec, '/', -1, false);
+      wpi::split(path, pathSplitVec, '/', -1, false);
 
       // Find each individual item index
       int findusb = -1;
       int findtty = -1;
       int findregex = -1;
       for (size_t i = 0; i < pathSplitVec.size(); i++) {
-        if (findusb == -1 && pathSplitVec[i].equals("usb1")) {
+        if (findusb == -1 && wpi::equals(pathSplitVec[i], "usb1")) {
           findusb = i;
         }
-        if (findtty == -1 && pathSplitVec[i].equals("tty")) {
+        if (findtty == -1 && wpi::equals(pathSplitVec[i], "tty")) {
           findtty = i;
         }
-        if (findregex == -1 && pathSplitVec[i].equals(matchString)) {
+        if (findregex == -1 && wpi::equals(pathSplitVec[i], matchString)) {
           findregex = i;
         }
       }
 
       // Get the index for our device
       int hubIndex = findtty;
-      if (findtty == -1) hubIndex = findregex;
+      if (findtty == -1)
+        hubIndex = findregex;
 
       int devStart = findusb + 1;
 
-      if (hubIndex < devStart) continue;
+      if (hubIndex < devStart)
+        continue;
 
       // Add our devices to our list
       m_unsortedHubPath.emplace_back(
-          wpi::StringRef{pathSplitVec[hubIndex - 2]});
+          std::string_view{pathSplitVec[hubIndex - 2]});
       m_visaResource.emplace_back(desc);
       m_osResource.emplace_back(
-          wpi::StringRef{osName}.split("(").second.split(")").first);
+          wpi::split(wpi::split(osName, "(").second, ")").first);
       break;
     }
   }
@@ -285,8 +292,9 @@
   if (portString.empty()) {
     for (size_t i = 0; i < 2; i++) {
       // Remove all used ports
-      auto idx = std::find(m_sortedHubPath.begin(), m_sortedHubPath.end(),
-                           m_usbNames[i]);
+      auto idx = std::find_if(
+          m_sortedHubPath.begin(), m_sortedHubPath.end(),
+          [&](const auto& s) { return wpi::equals(s, m_usbNames[i]); });
       if (idx != m_sortedHubPath.end()) {
         // found
         m_sortedHubPath.erase(idx);
@@ -321,7 +329,7 @@
   int retIndex = -1;
 
   for (size_t i = 0; i < m_sortedHubPath.size(); i++) {
-    if (m_sortedHubPath[i].equals(portString)) {
+    if (wpi::equals(m_sortedHubPath[i], portString)) {
       retIndex = i;
       break;
     }
diff --git a/hal/src/main/native/athena/ctre/CtreCanNode.cpp b/hal/src/main/native/athena/ctre/CtreCanNode.cpp
deleted file mode 100644
index 440bebd..0000000
--- a/hal/src/main/native/athena/ctre/CtreCanNode.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-
-#include "CtreCanNode.h"
-#include "FRC_NetworkCommunication/CANSessionMux.h"
-#include <string.h> // memset
-
-static const UINT32 kFullMessageIDMask = 0x1fffffff;
-
-CtreCanNode::CtreCanNode(UINT8 deviceNumber)
-{
-	_deviceNumber = deviceNumber;
-}
-CtreCanNode::~CtreCanNode()
-{
-}
-void CtreCanNode::RegisterRx(uint32_t arbId)
-{
-	/* no need to do anything, we just use new API to poll last received message */
-}
-/**
- * Schedule a CAN Frame for periodic transmit.
- * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
- * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
- * @param dlc 		Number of bytes to transmit (0 to 8).
- * @param initialFrame	Ptr to the frame data to schedule for transmitting.  Passing null will result
- *						in defaulting to zero data value.
- */
-void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs, uint32_t dlc, const uint8_t * initialFrame)
-{
-	int32_t status = 0;
-	if(dlc > 8)
-		dlc = 8;
-	txJob_t job = {0};
-	job.arbId = arbId;
-	job.periodMs = periodMs;
-	job.dlc = dlc;
-	if(initialFrame){
-		/* caller wants to specify original data */
-		memcpy(job.toSend, initialFrame, dlc);
-	}
-	_txJobs[arbId] = job;
-	FRC_NetworkCommunication_CANSessionMux_sendMessage(	job.arbId,
-														job.toSend,
-														job.dlc,
-														job.periodMs,
-														&status);
-}
-/**
- * Schedule a CAN Frame for periodic transmit.  Assume eight byte DLC and zero value for initial transmission.
- * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
- * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
- */
-void CtreCanNode::RegisterTx(uint32_t arbId, uint32_t periodMs)
-{
-	RegisterTx(arbId,periodMs, 8, 0);
-}
-/**
- * Remove a CAN frame Arbid to stop transmission.
- * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
- */
-void CtreCanNode::UnregisterTx(uint32_t arbId)
-{
-	/* set period to zero */
-	ChangeTxPeriod(arbId, 0);
-	/* look and remove */
-	txJobs_t::iterator iter = _txJobs.find(arbId);
-	if(iter != _txJobs.end()) {
-		_txJobs.erase(iter);
-	}
-}
-static int64_t GetTimeMs() {
-	std::chrono::time_point < std::chrono::system_clock > now;
-	now = std::chrono::system_clock::now();
-	auto duration = now.time_since_epoch();
-	auto millis = std::chrono::duration_cast < std::chrono::milliseconds
-					> (duration).count();
-	return (int64_t) millis;
-}
-CTR_Code CtreCanNode::GetRx(uint32_t arbId,uint8_t * dataBytes, uint32_t timeoutMs)
-{
-	CTR_Code retval = CTR_OKAY;
-	int32_t status = 0;
-	uint8_t len = 0;
-	uint32_t timeStamp;
-	/* cap timeout at 999ms */
-	if(timeoutMs > 999)
-		timeoutMs = 999;
-	FRC_NetworkCommunication_CANSessionMux_receiveMessage(&arbId,kFullMessageIDMask,dataBytes,&len,&timeStamp,&status);
-	std::scoped_lock lock(_lck);
-	if(status == 0){
-		/* fresh update */
-		rxEvent_t & r = _rxRxEvents[arbId]; /* lookup entry or make a default new one with all zeroes */
-		r.time = GetTimeMs();
-		memcpy(r.bytes,  dataBytes,  8);	/* fill in databytes */
-	}else{
-		/* did not get the message */
-		rxRxEvents_t::iterator i = _rxRxEvents.find(arbId);
-		if(i == _rxRxEvents.end()){
-			/* we've never gotten this mesage */
-			retval = CTR_RxTimeout;
-			/* fill caller's buffer with zeros */
-			memset(dataBytes,0,8);
-		}else{
-			/* we've gotten this message before but not recently */
-			memcpy(dataBytes,i->second.bytes,8);
-			/* get the time now */
-			int64_t now = GetTimeMs(); /* get now */
-			/* how long has it been? */
-			int64_t temp = now - i->second.time; /* temp = now - last */
-			if (temp > ((int64_t) timeoutMs)) {
-					retval = CTR_RxTimeout;
-			} else {
-					/* our last update was recent enough */
-			}
-		}
-	}
-
-	return retval;
-}
-void CtreCanNode::FlushTx(uint32_t arbId)
-{
-	int32_t status = 0;
-	txJobs_t::iterator iter = _txJobs.find(arbId);
-	if(iter != _txJobs.end())
-		FRC_NetworkCommunication_CANSessionMux_sendMessage(	iter->second.arbId,
-															iter->second.toSend,
-															iter->second.dlc,
-															iter->second.periodMs,
-															&status);
-}
-/**
- * Change the transmit period of an already scheduled CAN frame.
- * This keeps the frame payload contents the same without caller having to perform
- * a read-modify-write.
- * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
- * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
- * @return true if scheduled job was found and updated, false if there was no preceding job for the specified arbID.
- */
-bool CtreCanNode::ChangeTxPeriod(uint32_t arbId, uint32_t periodMs)
-{
-	int32_t status = 0;
-	/* lookup the data bytes and period for this message */
-	txJobs_t::iterator iter = _txJobs.find(arbId);
-	if(iter != _txJobs.end()) {
-		/* modify th periodMs */
-		iter->second.periodMs = periodMs;
-		/* reinsert into scheduler with the same data bytes, only the period changed. */
-		FRC_NetworkCommunication_CANSessionMux_sendMessage(	iter->second.arbId,
-															iter->second.toSend,
-															iter->second.dlc,
-															iter->second.periodMs,
-															&status);
-		return true;
-	}
-	return false;
-}
-
diff --git a/hal/src/main/native/athena/ctre/CtreCanNode.h b/hal/src/main/native/athena/ctre/CtreCanNode.h
deleted file mode 100644
index ce2d6ac..0000000
--- a/hal/src/main/native/athena/ctre/CtreCanNode.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef CtreCanNode_H_
-#define CtreCanNode_H_
-#include "ctre.h"				//BIT Defines + Typedefs
-#include <map>
-#include <wpi/mutex.h>
-class CtreCanNode
-{
-public:
-	CtreCanNode(UINT8 deviceNumber);
-    ~CtreCanNode();
-
-	UINT8 GetDeviceNumber()
-	{
-		return _deviceNumber;
-	}
-protected:
-
-
-	template <typename T> class txTask{
-		public:
-			uint32_t arbId;
-			T * toSend;
-			T * operator -> ()
-			{
-				return toSend;
-			}
-			T & operator*()
-			{
-				return *toSend;
-			}
-			bool IsEmpty()
-			{
-				if(toSend == 0)
-					return true;
-				return false;
-			}
-	};
-	template <typename T> class recMsg{
-		public:
-			uint32_t arbId;
-			uint8_t bytes[8];
-			CTR_Code err;
-			T * operator -> ()
-			{
-				return (T *)bytes;
-			}
-			T & operator*()
-			{
-				return *(T *)bytes;
-			}
-	};
-	UINT8 _deviceNumber;
-	void RegisterRx(uint32_t arbId);
-	/**
-	 * Schedule a CAN Frame for periodic transmit.  Assume eight byte DLC and zero value for initial transmission.
-	 * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
-	 * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
-	 */
-	void RegisterTx(uint32_t arbId, uint32_t periodMs);
-	/**
-	 * Schedule a CAN Frame for periodic transmit.
-	 * @param arbId 	CAN Frame Arbitration ID.  Set BIT31 for 11bit ids, otherwise we use 29bit ids.
-	 * @param periodMs	Period to transmit CAN frame.  Pass 0 for one-shot, which also disables that ArbID's preceding periodic transmit.
-	 * @param dlc 		Number of bytes to transmit (0 to 8).
-	 * @param initialFrame	Ptr to the frame data to schedule for transmitting.  Passing null will result
-	 *						in defaulting to zero data value.
-	 */
-	void RegisterTx(uint32_t arbId, uint32_t periodMs, uint32_t dlc, const uint8_t * initialFrame);
-	void UnregisterTx(uint32_t arbId);
-
-	CTR_Code GetRx(uint32_t arbId,uint8_t * dataBytes,uint32_t timeoutMs);
-	void FlushTx(uint32_t arbId);
-	bool ChangeTxPeriod(uint32_t arbId, uint32_t periodMs);
-
-	template<typename T> txTask<T> GetTx(uint32_t arbId)
-	{
-		txTask<T> retval = {0, nullptr};
-		txJobs_t::iterator i = _txJobs.find(arbId);
-		if(i != _txJobs.end()){
-			retval.arbId = i->second.arbId;
-			retval.toSend = (T*)i->second.toSend;
-		}
-		return retval;
-	}
-	template<class T> void FlushTx(T & par)
-	{
-		FlushTx(par.arbId);
-	}
-
-	template<class T> recMsg<T> GetRx(uint32_t arbId, uint32_t timeoutMs)
-	{
-		recMsg<T> retval;
-		retval.err = GetRx(arbId,retval.bytes, timeoutMs);
-		return retval;
-	}
-
-private:
-
-	class txJob_t {
-		public:
-			uint32_t arbId;
-			uint8_t toSend[8];
-			uint32_t periodMs;
-			uint8_t dlc;
-	};
-
-	class rxEvent_t{
-		public:
-			uint8_t bytes[8];
-			int64_t time;
-			rxEvent_t()
-			{
-				bytes[0] = 0;
-				bytes[1] = 0;
-				bytes[2] = 0;
-				bytes[3] = 0;
-				bytes[4] = 0;
-				bytes[5] = 0;
-				bytes[6] = 0;
-				bytes[7] = 0;
-			}
-	};
-
-	typedef std::map<uint32_t,txJob_t> txJobs_t;
-	txJobs_t _txJobs;
-
-	typedef std::map<uint32_t,rxEvent_t> rxRxEvents_t;
-	rxRxEvents_t _rxRxEvents;
-
-	wpi::mutex _lck;
-};
-#endif
diff --git a/hal/src/main/native/athena/ctre/PCM.cpp b/hal/src/main/native/athena/ctre/PCM.cpp
deleted file mode 100644
index 4fd633f..0000000
--- a/hal/src/main/native/athena/ctre/PCM.cpp
+++ /dev/null
@@ -1,573 +0,0 @@
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-
-#include "PCM.h"
-#include "FRC_NetworkCommunication/CANSessionMux.h"
-/* This can be a constant, as long as nobody needs to update solenoids within
-    1/50 of a second. */
-static const INT32 kCANPeriod = 20;
-
-#define STATUS_1  			0x9041400
-#define STATUS_SOL_FAULTS  	0x9041440
-#define STATUS_DEBUG  		0x9041480
-
-#define EXPECTED_RESPONSE_TIMEOUT_MS	(50)
-#define GET_PCM_STATUS()			CtreCanNode::recMsg<PcmStatus_t> 		rx = GetRx<PcmStatus_t>			(STATUS_1|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
-#define GET_PCM_SOL_FAULTS()		CtreCanNode::recMsg<PcmStatusFault_t> 	rx = GetRx<PcmStatusFault_t>	(STATUS_SOL_FAULTS|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
-#define GET_PCM_DEBUG()				CtreCanNode::recMsg<PcmDebug_t> 		rx = GetRx<PcmDebug_t>			(STATUS_DEBUG|GetDeviceNumber(),EXPECTED_RESPONSE_TIMEOUT_MS)
-
-#define CONTROL_1 			0x09041C00	/* PCM_Control */
-#define CONTROL_2 			0x09041C40	/* PCM_SupplemControl */
-#define CONTROL_3 			0x09041C80	/* PcmControlSetOneShotDur_t */
-
-/* encoder/decoders */
-typedef struct _PcmStatus_t{
-	/* Byte 0 */
-	unsigned SolenoidBits:8;
-	/* Byte 1 */
-	unsigned compressorOn:1;
-	unsigned stickyFaultFuseTripped:1;
-	unsigned stickyFaultCompCurrentTooHigh:1;
-	unsigned faultFuseTripped:1;
-	unsigned faultCompCurrentTooHigh:1;
-	unsigned faultHardwareFailure:1;
-	unsigned isCloseloopEnabled:1;
-	unsigned pressureSwitchEn:1;
-	/* Byte 2*/
-	unsigned battVoltage:8;
-	/* Byte 3 */
-	unsigned solenoidVoltageTop8:8;
-	/* Byte 4 */
-	unsigned compressorCurrentTop6:6;
-	unsigned solenoidVoltageBtm2:2;
-	/* Byte 5 */
-	unsigned StickyFault_dItooHigh :1;
-	unsigned Fault_dItooHigh :1;
-	unsigned moduleEnabled:1;
-	unsigned closedLoopOutput:1;
-	unsigned compressorCurrentBtm4:4;
-	/* Byte 6 */
-	unsigned tokenSeedTop8:8;
-	/* Byte 7 */
-	unsigned tokenSeedBtm8:8;
-}PcmStatus_t;
-
-typedef struct _PcmControl_t{
-	/* Byte 0 */
-	unsigned tokenTop8:8;
-	/* Byte 1 */
-	unsigned tokenBtm8:8;
-	/* Byte 2 */
-	unsigned solenoidBits:8;
-	/* Byte 3*/
-	unsigned reserved:4;
-	unsigned closeLoopOutput:1;
-	unsigned compressorOn:1;
-	unsigned closedLoopEnable:1;
-	unsigned clearStickyFaults:1;
-	/* Byte 4 */
-	unsigned OneShotField_h8:8;
-	/* Byte 5 */
-	unsigned OneShotField_l8:8;
-}PcmControl_t;
-
-typedef struct _PcmControlSetOneShotDur_t{
-	uint8_t sol10MsPerUnit[8];
-}PcmControlSetOneShotDur_t;
-
-typedef struct _PcmStatusFault_t{
-	/* Byte 0 */
-	unsigned SolenoidBlacklist:8;
-	/* Byte 1 */
-	unsigned reserved_bit0 :1;
-	unsigned reserved_bit1 :1;
-	unsigned reserved_bit2 :1;
-	unsigned reserved_bit3 :1;
-	unsigned StickyFault_CompNoCurrent :1;
-	unsigned Fault_CompNoCurrent :1;
-	unsigned StickyFault_SolenoidJumper :1;
-	unsigned Fault_SolenoidJumper :1;
-}PcmStatusFault_t;
-
-typedef struct _PcmDebug_t{
-	unsigned tokFailsTop8:8;
-	unsigned tokFailsBtm8:8;
-	unsigned lastFailedTokTop8:8;
-	unsigned lastFailedTokBtm8:8;
-	unsigned tokSuccessTop8:8;
-	unsigned tokSuccessBtm8:8;
-}PcmDebug_t;
-
-
-/* PCM Constructor - Clears all vars, establishes default settings, starts PCM background process
- *
- * @Return	-	void
- *
- * @Param 	-	deviceNumber	- 	Device ID of PCM to be controlled
- */
-PCM::PCM(UINT8 deviceNumber): CtreCanNode(deviceNumber)
-{
-	RegisterRx(STATUS_1 | deviceNumber );
-	RegisterRx(STATUS_SOL_FAULTS | deviceNumber );
-	RegisterRx(STATUS_DEBUG | deviceNumber );
-	RegisterTx(CONTROL_1 | deviceNumber, kCANPeriod);
-	/* enable close loop */
-	SetClosedLoopControl(1);
-}
-/* PCM D'tor
- */
-PCM::~PCM()
-{
-
-}
-
-/* Set PCM solenoid state
- *
- * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
- *
- * @Param 	-	idx			- 	ID of solenoid (0-7)
- * @Param 	-	en			- 	Enable / Disable identified solenoid
- */
-CTR_Code PCM::SetSolenoid(unsigned char idx, bool en)
-{
-	CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
-	if(toFill.IsEmpty())return CTR_UnexpectedArbId;
-	if (en)
-		toFill->solenoidBits |= (1ul << (idx));
-	else
-		toFill->solenoidBits &= ~(1ul << (idx));
-	FlushTx(toFill);
-	return CTR_OKAY;
-}
-
-/* Set all PCM solenoid states
- *
- * @Return	-	CTR_Code	-	Error code (if any) for setting solenoids
- * @Param 	-	state			Bitfield to set all solenoids to
- */
-CTR_Code PCM::SetAllSolenoids(UINT8 state) {
-	CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
-	if(toFill.IsEmpty())return CTR_UnexpectedArbId;
-	toFill->solenoidBits = state;
-	FlushTx(toFill);
-	return CTR_OKAY;
-}
-
-/* Clears PCM sticky faults (indicators of past faults
- *
- * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
- *
- * @Param 	-	clr		- 	Clear / do not clear faults
- */
-CTR_Code PCM::ClearStickyFaults()
-{
-	int32_t status = 0;
-	uint8_t pcmSupplemControl[] = { 0, 0, 0, 0x80 }; /* only bit set is ClearStickyFaults */
-	FRC_NetworkCommunication_CANSessionMux_sendMessage(CONTROL_2  | GetDeviceNumber(), pcmSupplemControl, sizeof(pcmSupplemControl), 0, &status);
-	if(status)
-		return CTR_TxFailed;
-	return CTR_OKAY;
-}
-
-/* Enables PCM Closed Loop Control of Compressor via pressure switch
- *
- * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
- *
- * @Param 	-	en		- 	Enable / Disable Closed Loop Control
- */
-CTR_Code PCM::SetClosedLoopControl(bool en)
-{
-	CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
-	if(toFill.IsEmpty())return CTR_UnexpectedArbId;
-	toFill->closedLoopEnable = en;
-	FlushTx(toFill);
-	return CTR_OKAY;
-}
-/* Get solenoid Blacklist status
- * @Return	-	CTR_Code	-	Error code (if any)
- * @Param	-	idx			-	ID of solenoid [0,7] to fire one shot pulse.
- */
-CTR_Code PCM::FireOneShotSolenoid(UINT8 idx)
-{
-	CtreCanNode::txTask<PcmControl_t> toFill = GetTx<PcmControl_t>(CONTROL_1 | GetDeviceNumber());
-	if(toFill.IsEmpty())return CTR_UnexpectedArbId;
-	/* grab field as it is now */
-	uint16_t oneShotField;
-	oneShotField = toFill->OneShotField_h8;
-	oneShotField <<= 8;
-	oneShotField |= toFill->OneShotField_l8;
-	/* get the caller's channel */
-	uint16_t shift = 2*idx;
-	uint16_t mask = 3; /* two bits wide */
-	uint8_t chBits = (oneShotField >> shift) & mask;
-	/* flip it */
-	chBits = (chBits)%3 + 1;
-	/* clear out 2bits for this channel*/
-	oneShotField &= ~(mask << shift);
-	/* put new field in */
-	oneShotField |= chBits << shift;
-	/* apply field as it is now */
-	toFill->OneShotField_h8 = oneShotField >> 8;
-	toFill->OneShotField_l8 = oneShotField;
-	FlushTx(toFill);
-	return CTR_OKAY;
-}
-/* Configure the pulse width of a solenoid channel for one-shot pulse.
- * Preprogrammed pulsewidth is 10ms resolution and can be between 10ms and
- * 2.55s.
- *
- * @Return	-	CTR_Code	-	Error code (if any)
- * @Param	-	idx			-	ID of solenoid [0,7] to configure.
- * @Param	-	durMs		-	pulse width in ms.
- */
-CTR_Code PCM::SetOneShotDurationMs(UINT8 idx,uint32_t durMs)
-{
-	/* sanity check caller's param */
-	if(idx > 7)
-		return CTR_InvalidParamValue;
-	/* get latest tx frame */
-	CtreCanNode::txTask<PcmControlSetOneShotDur_t> toFill = GetTx<PcmControlSetOneShotDur_t>(CONTROL_3 | GetDeviceNumber());
-	if(toFill.IsEmpty()){
-		/* only send this out if caller wants to do one-shots */
-		RegisterTx(CONTROL_3 | _deviceNumber, kCANPeriod);
-		/* grab it */
-		toFill = GetTx<PcmControlSetOneShotDur_t>(CONTROL_3 | GetDeviceNumber());
-	}
-	toFill->sol10MsPerUnit[idx] = std::min(durMs/10,(uint32_t)0xFF);
-	/* apply the new data bytes */
-	FlushTx(toFill);
-	return CTR_OKAY;
-}
-
-/* Get solenoid state
- *
- * @Return	-	True/False	-	True if solenoid enabled, false otherwise
- *
- * @Param 	-	idx		- 	ID of solenoid (0-7) to return status of
- */
-CTR_Code PCM::GetSolenoid(UINT8 idx, bool &status)
-{
-	GET_PCM_STATUS();
-	status = (rx->SolenoidBits & (1ul<<(idx)) ) ? 1 : 0;
-	return rx.err;
-}
-
-/* Get solenoid state for all solenoids on the PCM
- *
- * @Return	-	Bitfield of solenoid states
- */
-CTR_Code PCM::GetAllSolenoids(UINT8 &status)
-{
-	GET_PCM_STATUS();
-	status = rx->SolenoidBits;
-	return rx.err;
-}
-
-/* Get pressure switch state
- *
- * @Return	-	True/False	-	True if pressure adequate, false if low
- */
-CTR_Code PCM::GetPressure(bool &status)
-{
-	GET_PCM_STATUS();
-	status = (rx->pressureSwitchEn ) ? 1 : 0;
-	return rx.err;
-}
-
-/* Get compressor state
- *
- * @Return	-	True/False	-	True if enabled, false if otherwise
- */
-CTR_Code PCM::GetCompressor(bool &status)
-{
-	GET_PCM_STATUS();
-	status = (rx->compressorOn);
-	return rx.err;
-}
-
-/* Get closed loop control state
- *
- * @Return	-	True/False	-	True if closed loop enabled, false if otherwise
- */
-CTR_Code PCM::GetClosedLoopControl(bool &status)
-{
-	GET_PCM_STATUS();
-	status = (rx->isCloseloopEnabled);
-	return rx.err;
-}
-
-/* Get compressor current draw
- *
- * @Return	-	Amperes	-	Compressor current
- */
-CTR_Code PCM::GetCompressorCurrent(float &status)
-{
-	GET_PCM_STATUS();
-	uint32_t temp =(rx->compressorCurrentTop6);
-	temp <<= 4;
-	temp |=  rx->compressorCurrentBtm4;
-	status = temp * 0.03125; /* 5.5 fixed pt value in Amps */
-	return rx.err;
-}
-
-/* Get voltage across solenoid rail
- *
- * @Return	-	Volts	-	Voltage across solenoid rail
- */
-CTR_Code PCM::GetSolenoidVoltage(float &status)
-{
-	GET_PCM_STATUS();
-	uint32_t raw =(rx->solenoidVoltageTop8);
-	raw <<= 2;
-	raw |=  rx->solenoidVoltageBtm2;
-	status = (double) raw * 0.03125; /* 5.5 fixed pt value in Volts */
-	return rx.err;
-}
-
-/* Get hardware fault value
- *
- * @Return	-	True/False	-	True if hardware failure detected, false if otherwise
- */
-CTR_Code PCM::GetHardwareFault(bool &status)
-{
-	GET_PCM_STATUS();
-	status = rx->faultHardwareFailure;
-	return rx.err;
-}
-
-/* Get compressor fault value
- *
- * @Return	-	True/False	-	True if shorted compressor detected, false if otherwise
- */
-CTR_Code PCM::GetCompressorCurrentTooHighFault(bool &status)
-{
-	GET_PCM_STATUS();
-	status = rx->faultCompCurrentTooHigh;
-	return rx.err;
-}
-CTR_Code PCM::GetCompressorShortedStickyFault(bool &status)
-{
-	GET_PCM_STATUS();
-	status = rx->StickyFault_dItooHigh;
-	return rx.err;
-}
-CTR_Code PCM::GetCompressorShortedFault(bool &status)
-{
-	GET_PCM_STATUS();
-	status = rx->Fault_dItooHigh;
-	return rx.err;
-}
-CTR_Code PCM::GetCompressorNotConnectedStickyFault(bool &status)
-{
-	GET_PCM_SOL_FAULTS();
-	status = rx->StickyFault_CompNoCurrent;
-	return rx.err;
-}
-CTR_Code PCM::GetCompressorNotConnectedFault(bool &status)
-{
-	GET_PCM_SOL_FAULTS();
-	status = rx->Fault_CompNoCurrent;
-	return rx.err;
-}
-
-/* Get solenoid fault value
- *
- * @Return	-	True/False	-	True if shorted solenoid detected, false if otherwise
- */
-CTR_Code PCM::GetSolenoidFault(bool &status)
-{
-	GET_PCM_STATUS();
-	status = rx->faultFuseTripped;
-	return rx.err;
-}
-
-/* Get compressor sticky fault value
- *
- * @Return	-	True/False	-	True if solenoid had previously been shorted
- * 								(and sticky fault was not cleared), false if otherwise
- */
-CTR_Code PCM::GetCompressorCurrentTooHighStickyFault(bool &status)
-{
-	GET_PCM_STATUS();
-	status = rx->stickyFaultCompCurrentTooHigh;
-	return rx.err;
-}
-
-/* Get solenoid sticky fault value
- *
- * @Return	-	True/False	-	True if compressor had previously been shorted
- * 								(and sticky fault was not cleared), false if otherwise
- */
-CTR_Code PCM::GetSolenoidStickyFault(bool &status)
-{
-	GET_PCM_STATUS();
-	status = rx->stickyFaultFuseTripped;
-	return rx.err;
-}
-/* Get battery voltage
- *
- * @Return	-	Volts	-	Voltage across PCM power ports
- */
-CTR_Code PCM::GetBatteryVoltage(float &status)
-{
-	GET_PCM_STATUS();
-	status = (float)rx->battVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
-	return rx.err;
-}
-/* Return status of module enable/disable
- *
- * @Return	-	bool		-	Returns TRUE if PCM is enabled, FALSE if disabled
- */
-CTR_Code PCM::isModuleEnabled(bool &status)
-{
-	GET_PCM_STATUS();
-	status = rx->moduleEnabled;
-	return rx.err;
-}
-/* Get number of total failed PCM Control Frame
- *
- * @Return	-	Failed Control Frames	-	Number of failed control frames (tokenization fails)
- *
- * @WARNING	-	Return only valid if [SeekDebugFrames] is enabled
- * 				See function SeekDebugFrames
- * 				See function EnableSeekDebugFrames
- */
-CTR_Code PCM::GetNumberOfFailedControlFrames(UINT16 &status)
-{
-	GET_PCM_DEBUG();
-	status = rx->tokFailsTop8;
-	status <<= 8;
-	status |= rx->tokFailsBtm8;
-	return rx.err;
-}
-/* Get raw Solenoid Blacklist
- *
- * @Return	-	BINARY	-	Raw binary breakdown of Solenoid Blacklist
- * 							BIT7 = Solenoid 1, BIT6 = Solenoid 2, etc.
- *
- * @WARNING	-	Return only valid if [SeekStatusFaultFrames] is enabled
- * 				See function SeekStatusFaultFrames
- * 				See function EnableSeekStatusFaultFrames
- */
-CTR_Code PCM::GetSolenoidBlackList(UINT8 &status)
-{
-	GET_PCM_SOL_FAULTS();
-	status = rx->SolenoidBlacklist;
-	return rx.err;
-}
-/* Get solenoid Blacklist status
- * - Blacklisted solenoids cannot be enabled until PCM is power cycled
- *
- * @Return	-	True/False	-	True if Solenoid is blacklisted, false if otherwise
- *
- * @Param	-	idx			-	ID of solenoid [0,7]
- *
- * @WARNING	-	Return only valid if [SeekStatusFaultFrames] is enabled
- * 				See function SeekStatusFaultFrames
- * 				See function EnableSeekStatusFaultFrames
- */
-CTR_Code PCM::IsSolenoidBlacklisted(UINT8 idx, bool &status)
-{
-	GET_PCM_SOL_FAULTS();
-	status = (rx->SolenoidBlacklist & (1ul<<(idx)) )? 1 : 0;
-	return rx.err;
-}
-//------------------ C interface --------------------------------------------//
-extern "C" {
-	void * c_PCM_Init(void) {
-		return new PCM();
-	}
-	CTR_Code c_SetSolenoid(void * handle, unsigned char idx, INT8 param) {
-		return ((PCM*) handle)->SetSolenoid(idx, param);
-	}
-	CTR_Code c_SetAllSolenoids(void * handle, UINT8 state) {
-		return ((PCM*) handle)->SetAllSolenoids(state);
-	}
-	CTR_Code c_SetClosedLoopControl(void * handle, INT8 param) {
-		return ((PCM*) handle)->SetClosedLoopControl(param);
-	}
-	CTR_Code c_ClearStickyFaults(void * handle, INT8 param) {
-		return ((PCM*) handle)->ClearStickyFaults();
-	}
-	CTR_Code c_GetSolenoid(void * handle, UINT8 idx, INT8 * status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetSolenoid(idx, bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetAllSolenoids(void * handle, UINT8 * status) {
-		return ((PCM*) handle)->GetAllSolenoids(*status);
-	}
-	CTR_Code c_GetPressure(void * handle, INT8 * status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetPressure(bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetCompressor(void * handle, INT8 * status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetCompressor(bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetClosedLoopControl(void * handle, INT8 * status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetClosedLoopControl(bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetCompressorCurrent(void * handle, float * status) {
-		CTR_Code retval = ((PCM*) handle)->GetCompressorCurrent(*status);
-		return retval;
-	}
-	CTR_Code c_GetSolenoidVoltage(void * handle, float*status) {
-		return ((PCM*) handle)->GetSolenoidVoltage(*status);
-	}
-	CTR_Code c_GetHardwareFault(void * handle, INT8*status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetHardwareFault(bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetCompressorFault(void * handle, INT8*status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetCompressorCurrentTooHighFault(bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetSolenoidFault(void * handle, INT8*status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetSolenoidFault(bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetCompressorStickyFault(void * handle, INT8*status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetCompressorCurrentTooHighStickyFault(bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetSolenoidStickyFault(void * handle, INT8*status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->GetSolenoidStickyFault(bstatus);
-		*status = bstatus;
-		return retval;
-	}
-	CTR_Code c_GetBatteryVoltage(void * handle, float*status) {
-		CTR_Code retval = ((PCM*) handle)->GetBatteryVoltage(*status);
-		return retval;
-	}
-	void c_SetDeviceNumber_PCM(void * handle, UINT8 deviceNumber) {
-	}
-	CTR_Code c_GetNumberOfFailedControlFrames(void * handle, UINT16*status) {
-		return ((PCM*) handle)->GetNumberOfFailedControlFrames(*status);
-	}
-	CTR_Code c_GetSolenoidBlackList(void * handle, UINT8 *status) {
-		return ((PCM*) handle)->GetSolenoidBlackList(*status);
-	}
-	CTR_Code c_IsSolenoidBlacklisted(void * handle, UINT8 idx, INT8*status) {
-		bool bstatus;
-		CTR_Code retval = ((PCM*) handle)->IsSolenoidBlacklisted(idx, bstatus);
-		*status = bstatus;
-		return retval;
-	}
-}
diff --git a/hal/src/main/native/athena/ctre/PCM.h b/hal/src/main/native/athena/ctre/PCM.h
deleted file mode 100644
index 4923202..0000000
--- a/hal/src/main/native/athena/ctre/PCM.h
+++ /dev/null
@@ -1,226 +0,0 @@
-#ifndef PCM_H_
-#define PCM_H_
-#include "ctre.h"				//BIT Defines + Typedefs
-#include "CtreCanNode.h"
-class PCM : public CtreCanNode
-{
-public:
-    PCM(UINT8 deviceNumber=0);
-    ~PCM();
-
-    /* Set PCM solenoid state
-     *
-     * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
-     * @Param 	-	idx			- 	ID of solenoid (0-7)
-     * @Param 	-	en			- 	Enable / Disable identified solenoid
-     */
-    CTR_Code 	SetSolenoid(unsigned char idx, bool en);
-
-    /* Set all PCM solenoid states
-     *
-     * @Return	-	CTR_Code	-	Error code (if any) for setting solenoids
-     * @Param 	-	state			Bitfield to set all solenoids to
-     */
-    CTR_Code 	SetAllSolenoids(UINT8 state);
-
-    /* Enables PCM Closed Loop Control of Compressor via pressure switch
-     * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
-     * @Param 	-	en		- 	Enable / Disable Closed Loop Control
-     */
-    CTR_Code 	SetClosedLoopControl(bool en);
-
-    /* Clears PCM sticky faults (indicators of past faults
-     * @Return	-	CTR_Code	-	Error code (if any) for setting solenoid
-     */
-    CTR_Code 	ClearStickyFaults();
-
-    /* Get solenoid state
-     *
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param 	-	idx		- 	ID of solenoid (0-7) to return if solenoid is on.
-     * @Param	-	status	-	true if solenoid enabled, false otherwise
-     */
-    CTR_Code 	GetSolenoid(UINT8 idx, bool &status);
-
-    /* Get state of all solenoids
-     *
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status	-	bitfield of solenoid states
-     */
-    CTR_Code 	GetAllSolenoids(UINT8 &status);
-
-    /* Get pressure switch state
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if pressure adequate, false if low
-     */
-    CTR_Code 	GetPressure(bool &status);
-
-    /* Get compressor state
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if compress output is on, false if otherwise
-     */
-    CTR_Code	GetCompressor(bool &status);
-
-    /* Get closed loop control state
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status	-	True if closed loop enabled, false if otherwise
-     */
-    CTR_Code 	GetClosedLoopControl(bool &status);
-
-    /* Get compressor current draw
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	Compressor current returned in Amperes (A)
-     */
-    CTR_Code 	GetCompressorCurrent(float &status);
-
-    /* Get voltage across solenoid rail
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	Voltage across solenoid rail in Volts (V)
-     */
-    CTR_Code 	GetSolenoidVoltage(float &status);
-
-    /* Get hardware fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if hardware failure detected, false if otherwise
-     */
-    CTR_Code 	GetHardwareFault(bool &status);
-
-    /* Get compressor fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if abnormally high compressor current detected, false if otherwise
-     */
-    CTR_Code 	GetCompressorCurrentTooHighFault(bool &status);
-
-    /* Get solenoid fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if shorted solenoid detected, false if otherwise
-     */
-    CTR_Code 	GetSolenoidFault(bool &status);
-
-    /* Get compressor sticky fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if solenoid had previously been shorted
-     * 								(and sticky fault was not cleared), false if otherwise
-     */
-    CTR_Code 	GetCompressorCurrentTooHighStickyFault(bool &status);
-    /* Get compressor shorted sticky fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if compressor output is shorted, false if otherwise
-     */
-    CTR_Code 	GetCompressorShortedStickyFault(bool &status);
-    /* Get compressor shorted fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if compressor output is shorted, false if otherwise
-     */
-    CTR_Code 	GetCompressorShortedFault(bool &status);
-    /* Get compressor is not connected sticky fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if compressor current is too low,
-     * 					indicating compressor is not connected, false if otherwise
-     */
-    CTR_Code 	GetCompressorNotConnectedStickyFault(bool &status);
-    /* Get compressor is not connected fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if compressor current is too low,
-     * 					indicating compressor is not connected, false if otherwise
-     */
-    CTR_Code 	GetCompressorNotConnectedFault(bool &status);
-
-    /* Get solenoid sticky fault value
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	True if compressor had previously been shorted
-     * 								(and sticky fault was not cleared), false if otherwise
-     */
-    CTR_Code 	GetSolenoidStickyFault(bool &status);
-
-    /* Get battery voltage
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	Voltage across PCM power ports in Volts (V)
-     */
-    CTR_Code 	GetBatteryVoltage(float &status);
-
-    /* Set PCM Device Number and according CAN frame IDs
-     * @Return	-	void
-     * @Param	-	deviceNumber	-	Device number of PCM to control
-     */
-    void	SetDeviceNumber(UINT8 deviceNumber);
-    /* Get number of total failed PCM Control Frame
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	Number of failed control frames (tokenization fails)
-     * @WARNING	-	Return only valid if [SeekDebugFrames] is enabled
-     * 				See function SeekDebugFrames
-     * 				See function EnableSeekDebugFrames
-     */
-	CTR_Code GetNumberOfFailedControlFrames(UINT16 &status);
-
-    /* Get raw Solenoid Blacklist
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	Raw binary breakdown of Solenoid Blacklist
-     * 								BIT7 = Solenoid 1, BIT6 = Solenoid 2, etc.
-     * @WARNING	-	Return only valid if [SeekStatusFaultFrames] is enabled
-     * 				See function SeekStatusFaultFrames
-     * 				See function EnableSeekStatusFaultFrames
-     */
-    CTR_Code 	GetSolenoidBlackList(UINT8 &status);
-
-    /* Get solenoid Blacklist status
-     * - Blacklisted solenoids cannot be enabled until PCM is power cycled
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	idx			-	ID of solenoid [0,7]
-     * @Param	-	status		-	True if Solenoid is blacklisted, false if otherwise
-     * @WARNING	-	Return only valid if [SeekStatusFaultFrames] is enabled
-     * 				See function SeekStatusFaultFrames
-     * 				See function EnableSeekStatusFaultFrames
-     */
-    CTR_Code 	IsSolenoidBlacklisted(UINT8 idx, bool &status);
-
-    /* Return status of module enable/disable
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	status		-	Returns TRUE if PCM is enabled, FALSE if disabled
-     */
-    CTR_Code	isModuleEnabled(bool &status);
-
-    /* Get solenoid Blacklist status
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	idx			-	ID of solenoid [0,7] to fire one shot pulse.
-     */
-    CTR_Code FireOneShotSolenoid(UINT8 idx);
-
-    /* Configure the pulse width of a solenoid channel for one-shot pulse.
-	 * Preprogrammed pulsewidth is 10ms resolute and can be between 20ms and 5.1s.
-     * @Return	-	CTR_Code	-	Error code (if any)
-     * @Param	-	idx			-	ID of solenoid [0,7] to configure.
-     * @Param	-	durMs		-	pulse width in ms.
-     */
-    CTR_Code SetOneShotDurationMs(UINT8 idx,uint32_t durMs);
-
-};
-//------------------ C interface --------------------------------------------//
-extern "C" {
-	void * c_PCM_Init(void);
-	CTR_Code c_SetSolenoid(void * handle,unsigned char idx,INT8 param);
-	CTR_Code c_SetAllSolenoids(void * handle,UINT8 state);
-	CTR_Code c_SetClosedLoopControl(void * handle,INT8 param);
-	CTR_Code c_ClearStickyFaults(void * handle,INT8 param);
-	CTR_Code c_GetSolenoid(void * handle,UINT8 idx,INT8 * status);
-	CTR_Code c_GetAllSolenoids(void * handle,UINT8 * status);
-	CTR_Code c_GetPressure(void * handle,INT8 * status);
-	CTR_Code c_GetCompressor(void * handle,INT8 * status);
-	CTR_Code c_GetClosedLoopControl(void * handle,INT8 * status);
-	CTR_Code c_GetCompressorCurrent(void * handle,float * status);
-	CTR_Code c_GetSolenoidVoltage(void * handle,float*status);
-	CTR_Code c_GetHardwareFault(void * handle,INT8*status);
-	CTR_Code c_GetCompressorFault(void * handle,INT8*status);
-	CTR_Code c_GetSolenoidFault(void * handle,INT8*status);
-	CTR_Code c_GetCompressorStickyFault(void * handle,INT8*status);
-	CTR_Code c_GetSolenoidStickyFault(void * handle,INT8*status);
-	CTR_Code c_GetBatteryVoltage(void * handle,float*status);
-	void c_SetDeviceNumber_PCM(void * handle,UINT8 deviceNumber);
-	void c_EnableSeekStatusFrames(void * handle,INT8 enable);
-	void c_EnableSeekStatusFaultFrames(void * handle,INT8 enable);
-	void c_EnableSeekDebugFrames(void * handle,INT8 enable);
-	CTR_Code c_GetNumberOfFailedControlFrames(void * handle,UINT16*status);
-	CTR_Code c_GetSolenoidBlackList(void * handle,UINT8 *status);
-	CTR_Code c_IsSolenoidBlacklisted(void * handle,UINT8 idx,INT8*status);
-}
-#endif
diff --git a/hal/src/main/native/athena/ctre/ctre.h b/hal/src/main/native/athena/ctre/ctre.h
deleted file mode 100644
index 90d33c1..0000000
--- a/hal/src/main/native/athena/ctre/ctre.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * @file ctre.h
- * Common header for all CTRE HAL modules.
- */
-#ifndef CTRE_H
-#define CTRE_H
-
-//Bit Defines
-#define BIT0 0x01
-#define BIT1 0x02
-#define BIT2 0x04
-#define BIT3 0x08
-#define BIT4 0x10
-#define BIT5 0x20
-#define BIT6 0x40
-#define BIT7 0x80
-#define BIT8  0x0100
-#define BIT9  0x0200
-#define BIT10 0x0400
-#define BIT11 0x0800
-#define BIT12 0x1000
-#define BIT13 0x2000
-#define BIT14 0x4000
-#define BIT15 0x8000
-
-//Signed
-typedef	signed char	INT8;
-typedef	signed short	INT16;
-typedef	signed int	INT32;
-typedef	signed long long INT64;
-
-//Unsigned
-typedef	unsigned char	UINT8;
-typedef	unsigned short	UINT16;
-typedef	unsigned int	UINT32;
-typedef	unsigned long long UINT64;
-
-//Other
-typedef	unsigned char	UCHAR;
-typedef unsigned short	USHORT;
-typedef	unsigned int	UINT;
-typedef unsigned long	ULONG;
-
-typedef enum {
-		CTR_OKAY,				//!< No Error - Function executed as expected
-		CTR_RxTimeout,			//!< CAN frame has not been received within specified period of time.
-		CTR_TxTimeout,			//!< Not used.
-		CTR_InvalidParamValue, 	//!< Caller passed an invalid param
-		CTR_UnexpectedArbId,	//!< Specified CAN Id is invalid.
-		CTR_TxFailed,			//!< Could not transmit the CAN frame.
-		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;
-
-#endif /* CTRE_H */
diff --git a/hal/src/main/native/athena/mockdata/AccelerometerData.cpp b/hal/src/main/native/athena/mockdata/AccelerometerData.cpp
index 2baaf78..e097a24 100644
--- a/hal/src/main/native/athena/mockdata/AccelerometerData.cpp
+++ b/hal/src/main/native/athena/mockdata/AccelerometerData.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/simulation/AccelerometerData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/AddressableLEDData.cpp b/hal/src/main/native/athena/mockdata/AddressableLEDData.cpp
index d718789..a1d7011 100644
--- a/hal/src/main/native/athena/mockdata/AddressableLEDData.cpp
+++ b/hal/src/main/native/athena/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 "hal/simulation/AddressableLEDData.h"
 
@@ -11,7 +8,9 @@
 
 extern "C" {
 
-int32_t HALSIM_FindAddressableLEDForChannel(int32_t channel) { return 0; }
+int32_t HALSIM_FindAddressableLEDForChannel(int32_t channel) {
+  return 0;
+}
 
 void HALSIM_ResetAddressableLEDData(int32_t index) {}
 
diff --git a/hal/src/main/native/athena/mockdata/AnalogGyroData.cpp b/hal/src/main/native/athena/mockdata/AnalogGyroData.cpp
index d91ce27..b4ff695 100644
--- a/hal/src/main/native/athena/mockdata/AnalogGyroData.cpp
+++ b/hal/src/main/native/athena/mockdata/AnalogGyroData.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/simulation/AnalogGyroData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/AnalogInData.cpp b/hal/src/main/native/athena/mockdata/AnalogInData.cpp
index 4288538..30ac795 100644
--- a/hal/src/main/native/athena/mockdata/AnalogInData.cpp
+++ b/hal/src/main/native/athena/mockdata/AnalogInData.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/simulation/AnalogInData.h"
 
@@ -12,7 +9,9 @@
 extern "C" {
 void HALSIM_ResetAnalogInData(int32_t index) {}
 
-HAL_SimDeviceHandle HALSIM_GetAnalogInSimDevice(int32_t index) { return 0; }
+HAL_SimDeviceHandle HALSIM_GetAnalogInSimDevice(int32_t index) {
+  return 0;
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
   HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, AnalogIn##CAPINAME, RETURN)
diff --git a/hal/src/main/native/athena/mockdata/AnalogOutData.cpp b/hal/src/main/native/athena/mockdata/AnalogOutData.cpp
index f05b0be..e6da2aa 100644
--- a/hal/src/main/native/athena/mockdata/AnalogOutData.cpp
+++ b/hal/src/main/native/athena/mockdata/AnalogOutData.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/simulation/AnalogOutData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/AnalogTriggerData.cpp b/hal/src/main/native/athena/mockdata/AnalogTriggerData.cpp
index 7781cf2..af8d7cc 100644
--- a/hal/src/main/native/athena/mockdata/AnalogTriggerData.cpp
+++ b/hal/src/main/native/athena/mockdata/AnalogTriggerData.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/simulation/AnalogTriggerData.h"
 
@@ -11,7 +8,9 @@
 
 extern "C" {
 
-int32_t HALSIM_FindAnalogTriggerForChannel(int32_t channel) { return 0; }
+int32_t HALSIM_FindAnalogTriggerForChannel(int32_t channel) {
+  return 0;
+}
 
 void HALSIM_ResetAnalogTriggerData(int32_t index) {}
 
diff --git a/hal/src/main/native/athena/mockdata/CTREPCMData.cpp b/hal/src/main/native/athena/mockdata/CTREPCMData.cpp
new file mode 100644
index 0000000..fc9edfe
--- /dev/null
+++ b/hal/src/main/native/athena/mockdata/CTREPCMData.cpp
@@ -0,0 +1,38 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "hal/simulation/CTREPCMData.h"
+
+#include "hal/simulation/SimDataValue.h"
+
+extern "C" {
+void HALSIM_ResetCTREPCMData(int32_t index) {}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
+  HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, CTREPCM##CAPINAME, RETURN)
+
+HAL_SIMDATAVALUE_STUB_CAPI_CHANNEL(HAL_Bool, HALSIM, CTREPCMSolenoidOutput,
+                                   false)
+DEFINE_CAPI(HAL_Bool, Initialized, false)
+DEFINE_CAPI(HAL_Bool, CompressorOn, false)
+DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, false)
+DEFINE_CAPI(HAL_Bool, PressureSwitch, false)
+DEFINE_CAPI(double, CompressorCurrent, 0)
+
+void HALSIM_GetCTREPCMAllSolenoids(int32_t index, uint8_t* values) {
+  *values = 0;
+}
+
+void HALSIM_SetCTREPCMAllSolenoids(int32_t index, uint8_t values) {}
+
+void HALSIM_RegisterCTREPCMAllNonSolenoidCallbacks(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify) {}
+
+void HALSIM_RegisterCTREPCMAllSolenoidCallbacks(int32_t index, int32_t channel,
+                                                HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify) {}
+}  // extern "C"
diff --git a/hal/src/main/native/athena/mockdata/CanDataInternal.cpp b/hal/src/main/native/athena/mockdata/CanDataInternal.cpp
index 69debf0..be2fbc0 100644
--- a/hal/src/main/native/athena/mockdata/CanDataInternal.cpp
+++ b/hal/src/main/native/athena/mockdata/CanDataInternal.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/simulation/CanData.h"
 #include "hal/simulation/SimDataValue.h"
diff --git a/hal/src/main/native/athena/mockdata/DIOData.cpp b/hal/src/main/native/athena/mockdata/DIOData.cpp
index a06855d..392c31b 100644
--- a/hal/src/main/native/athena/mockdata/DIOData.cpp
+++ b/hal/src/main/native/athena/mockdata/DIOData.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/simulation/DIOData.h"
 
@@ -12,7 +9,9 @@
 extern "C" {
 void HALSIM_ResetDIOData(int32_t index) {}
 
-HAL_SimDeviceHandle HALSIM_GetDIOSimDevice(int32_t index) { return 0; }
+HAL_SimDeviceHandle HALSIM_GetDIOSimDevice(int32_t index) {
+  return 0;
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
   HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, DIO##CAPINAME, RETURN)
diff --git a/hal/src/main/native/athena/mockdata/DigitalPWMData.cpp b/hal/src/main/native/athena/mockdata/DigitalPWMData.cpp
index bcbe370..c3f5d31 100644
--- a/hal/src/main/native/athena/mockdata/DigitalPWMData.cpp
+++ b/hal/src/main/native/athena/mockdata/DigitalPWMData.cpp
@@ -1,16 +1,15 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "hal/simulation/DigitalPWMData.h"
 
 #include "hal/simulation/SimDataValue.h"
 
 extern "C" {
-int32_t HALSIM_FindDigitalPWMForChannel(int32_t channel) { return 0; }
+int32_t HALSIM_FindDigitalPWMForChannel(int32_t channel) {
+  return 0;
+}
 
 void HALSIM_ResetDigitalPWMData(int32_t index) {}
 
diff --git a/hal/src/main/native/athena/mockdata/DriverStationData.cpp b/hal/src/main/native/athena/mockdata/DriverStationData.cpp
index b4695ba..ba519fc 100644
--- a/hal/src/main/native/athena/mockdata/DriverStationData.cpp
+++ b/hal/src/main/native/athena/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 "hal/simulation/DriverStationData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/DutyCycleData.cpp b/hal/src/main/native/athena/mockdata/DutyCycleData.cpp
index 8d3cd61..d63e27e 100644
--- a/hal/src/main/native/athena/mockdata/DutyCycleData.cpp
+++ b/hal/src/main/native/athena/mockdata/DutyCycleData.cpp
@@ -1,22 +1,25 @@
-/*----------------------------------------------------------------------------*/
-/* 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/DutyCycleData.h"
 
 #include "hal/simulation/SimDataValue.h"
 
 extern "C" {
-int32_t HALSIM_FindDutyCycleForChannel(int32_t channel) { return 0; }
+int32_t HALSIM_FindDutyCycleForChannel(int32_t channel) {
+  return 0;
+}
 
 void HALSIM_ResetDutyCycleData(int32_t index) {}
 
-int32_t HALSIM_GetDutyCycleDigitalChannel(int32_t index) { return 0; }
+int32_t HALSIM_GetDutyCycleDigitalChannel(int32_t index) {
+  return 0;
+}
 
-HAL_SimDeviceHandle HALSIM_GetDutyCycleSimDevice(int32_t index) { return 0; }
+HAL_SimDeviceHandle HALSIM_GetDutyCycleSimDevice(int32_t index) {
+  return 0;
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
   HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, DutyCycle##CAPINAME, RETURN)
diff --git a/hal/src/main/native/athena/mockdata/EncoderData.cpp b/hal/src/main/native/athena/mockdata/EncoderData.cpp
index 87a7385..4b07b31 100644
--- a/hal/src/main/native/athena/mockdata/EncoderData.cpp
+++ b/hal/src/main/native/athena/mockdata/EncoderData.cpp
@@ -1,24 +1,29 @@
-/*----------------------------------------------------------------------------*/
-/* 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/simulation/EncoderData.h"
 
 #include "hal/simulation/SimDataValue.h"
 
 extern "C" {
-int32_t HALSIM_FindEncoderForChannel(int32_t channel) { return 0; }
+int32_t HALSIM_FindEncoderForChannel(int32_t channel) {
+  return 0;
+}
 
 void HALSIM_ResetEncoderData(int32_t index) {}
 
-int32_t HALSIM_GetEncoderDigitalChannelA(int32_t index) { return 0; }
+int32_t HALSIM_GetEncoderDigitalChannelA(int32_t index) {
+  return 0;
+}
 
-int32_t HALSIM_GetEncoderDigitalChannelB(int32_t index) { return 0; }
+int32_t HALSIM_GetEncoderDigitalChannelB(int32_t index) {
+  return 0;
+}
 
-HAL_SimDeviceHandle HALSIM_GetEncoderSimDevice(int32_t index) { return 0; }
+HAL_SimDeviceHandle HALSIM_GetEncoderSimDevice(int32_t index) {
+  return 0;
+}
 
 #define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
   HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, Encoder##CAPINAME, RETURN)
@@ -35,11 +40,15 @@
 
 void HALSIM_SetEncoderDistance(int32_t index, double distance) {}
 
-double HALSIM_GetEncoderDistance(int32_t index) { return 0; }
+double HALSIM_GetEncoderDistance(int32_t index) {
+  return 0;
+}
 
 void HALSIM_SetEncoderRate(int32_t index, double rate) {}
 
-double HALSIM_GetEncoderRate(int32_t index) { return 0; }
+double HALSIM_GetEncoderRate(int32_t index) {
+  return 0;
+}
 
 void HALSIM_RegisterEncoderAllCallbacks(int32_t index,
                                         HAL_NotifyCallback callback,
diff --git a/hal/src/main/native/athena/mockdata/I2CData.cpp b/hal/src/main/native/athena/mockdata/I2CData.cpp
index eb6a6c9..2f91061 100644
--- a/hal/src/main/native/athena/mockdata/I2CData.cpp
+++ b/hal/src/main/native/athena/mockdata/I2CData.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/simulation/I2CData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/MockHooks.cpp b/hal/src/main/native/athena/mockdata/MockHooks.cpp
index 2e7bcfe..0ea05d0 100644
--- a/hal/src/main/native/athena/mockdata/MockHooks.cpp
+++ b/hal/src/main/native/athena/mockdata/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 "hal/simulation/MockHooks.h"
 
@@ -15,7 +12,9 @@
 
 void HALSIM_SetProgramStarted(void) {}
 
-HAL_Bool HALSIM_GetProgramStarted(void) { return false; }
+HAL_Bool HALSIM_GetProgramStarted(void) {
+  return false;
+}
 
 void HALSIM_RestartTiming(void) {}
 
@@ -23,7 +22,9 @@
 
 void HALSIM_ResumeTiming(void) {}
 
-HAL_Bool HALSIM_IsTimingPaused(void) { return false; }
+HAL_Bool HALSIM_IsTimingPaused(void) {
+  return false;
+}
 
 void HALSIM_StepTiming(uint64_t delta) {}
 
@@ -33,4 +34,18 @@
 
 void HALSIM_SetSendConsoleLine(HALSIM_SendConsoleLineHandler handler) {}
 
+int32_t HALSIM_RegisterSimPeriodicBeforeCallback(
+    HALSIM_SimPeriodicCallback callback, void* param) {
+  return 0;
+}
+
+void HALSIM_CancelSimPeriodicBeforeCallback(int32_t uid) {}
+
+int32_t HALSIM_RegisterSimPeriodicAfterCallback(
+    HALSIM_SimPeriodicCallback callback, void* param) {
+  return 0;
+}
+
+void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid) {}
+
 }  // extern "C"
diff --git a/hal/src/main/native/athena/mockdata/NotifierData.cpp b/hal/src/main/native/athena/mockdata/NotifierData.cpp
index 34aa6e7..f75733e 100644
--- a/hal/src/main/native/athena/mockdata/NotifierData.cpp
+++ b/hal/src/main/native/athena/mockdata/NotifierData.cpp
@@ -1,17 +1,18 @@
-/*----------------------------------------------------------------------------*/
-/* 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/simulation/NotifierData.h"
 
 extern "C" {
 
-uint64_t HALSIM_GetNextNotifierTimeout(void) { return 0; }
+uint64_t HALSIM_GetNextNotifierTimeout(void) {
+  return 0;
+}
 
-int32_t HALSIM_GetNumNotifiers(void) { return 0; }
+int32_t HALSIM_GetNumNotifiers(void) {
+  return 0;
+}
 
 int32_t HALSIM_GetNotifierInfo(struct HALSIM_NotifierInfo* arr, int32_t size) {
   return 0;
diff --git a/hal/src/main/native/athena/mockdata/PCMData.cpp b/hal/src/main/native/athena/mockdata/PCMData.cpp
deleted file mode 100644
index 29302cb..0000000
--- a/hal/src/main/native/athena/mockdata/PCMData.cpp
+++ /dev/null
@@ -1,40 +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/simulation/PCMData.h"
-
-#include "hal/simulation/SimDataValue.h"
-
-extern "C" {
-void HALSIM_ResetPCMData(int32_t index) {}
-
-#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
-  HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, PCM##CAPINAME, RETURN)
-
-HAL_SIMDATAVALUE_STUB_CAPI_CHANNEL(HAL_Bool, HALSIM, PCMSolenoidInitialized,
-                                   false)
-HAL_SIMDATAVALUE_STUB_CAPI_CHANNEL(HAL_Bool, HALSIM, PCMSolenoidOutput, false)
-DEFINE_CAPI(HAL_Bool, CompressorInitialized, false)
-DEFINE_CAPI(HAL_Bool, CompressorOn, false)
-DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, false)
-DEFINE_CAPI(HAL_Bool, PressureSwitch, false)
-DEFINE_CAPI(double, CompressorCurrent, 0)
-
-void HALSIM_GetPCMAllSolenoids(int32_t index, uint8_t* values) { *values = 0; }
-
-void HALSIM_SetPCMAllSolenoids(int32_t index, uint8_t values) {}
-
-void HALSIM_RegisterPCMAllNonSolenoidCallbacks(int32_t index,
-                                               HAL_NotifyCallback callback,
-                                               void* param,
-                                               HAL_Bool initialNotify) {}
-
-void HALSIM_RegisterPCMAllSolenoidCallbacks(int32_t index, int32_t channel,
-                                            HAL_NotifyCallback callback,
-                                            void* param,
-                                            HAL_Bool initialNotify) {}
-}  // extern "C"
diff --git a/hal/src/main/native/athena/mockdata/PDPData.cpp b/hal/src/main/native/athena/mockdata/PDPData.cpp
deleted file mode 100644
index a28bb81..0000000
--- a/hal/src/main/native/athena/mockdata/PDPData.cpp
+++ /dev/null
@@ -1,34 +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/simulation/PDPData.h"
-
-#include "../PortsInternal.h"
-#include "hal/simulation/SimDataValue.h"
-
-extern "C" {
-void HALSIM_ResetPDPData(int32_t index) {}
-
-#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
-  HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, PDP##CAPINAME, RETURN)
-
-DEFINE_CAPI(HAL_Bool, Initialized, false)
-DEFINE_CAPI(double, Temperature, 0)
-DEFINE_CAPI(double, Voltage, 0)
-HAL_SIMDATAVALUE_STUB_CAPI_CHANNEL(double, HALSIM, PDPCurrent, 0)
-
-void HALSIM_GetPDPAllCurrents(int32_t index, double* currents) {
-  for (int i = 0; i < hal::kNumPDPChannels; i++) currents[i] = 0;
-}
-
-void HALSIM_SetPDPAllCurrents(int32_t index, const double* currents) {}
-
-void HALSIM_RegisterPDPAllNonCurrentCallbacks(int32_t index, int32_t channel,
-                                              HAL_NotifyCallback callback,
-                                              void* param,
-                                              HAL_Bool initialNotify) {}
-}  // extern "C"
diff --git a/hal/src/main/native/athena/mockdata/PWMData.cpp b/hal/src/main/native/athena/mockdata/PWMData.cpp
index b9c5691..3e12398 100644
--- a/hal/src/main/native/athena/mockdata/PWMData.cpp
+++ b/hal/src/main/native/athena/mockdata/PWMData.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/simulation/PWMData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/PowerDistributionData.cpp b/hal/src/main/native/athena/mockdata/PowerDistributionData.cpp
new file mode 100644
index 0000000..a44e222
--- /dev/null
+++ b/hal/src/main/native/athena/mockdata/PowerDistributionData.cpp
@@ -0,0 +1,35 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "hal/simulation/PowerDistributionData.h"
+
+#include "../PortsInternal.h"
+#include "hal/simulation/SimDataValue.h"
+
+extern "C" {
+void HALSIM_ResetPowerDistributionData(int32_t index) {}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
+  HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, PowerDistribution##CAPINAME, RETURN)
+
+DEFINE_CAPI(HAL_Bool, Initialized, false)
+DEFINE_CAPI(double, Temperature, 0)
+DEFINE_CAPI(double, Voltage, 0)
+HAL_SIMDATAVALUE_STUB_CAPI_CHANNEL(double, HALSIM, PowerDistributionCurrent, 0)
+
+void HALSIM_GetPowerDistributionAllCurrents(int32_t index, double* currents,
+                                            int length) {
+  for (int i = 0; i < length; i++) {
+    currents[i] = 0;
+  }
+}
+
+void HALSIM_SetPowerDistributionAllCurrents(int32_t index,
+                                            const double* currents,
+                                            int length) {}
+
+void HALSIM_RegisterPowerDistributionAllNonCurrentCallbacks(
+    int32_t index, int32_t channel, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify) {}
+}  // extern "C"
diff --git a/hal/src/main/native/athena/mockdata/REVPHData.cpp b/hal/src/main/native/athena/mockdata/REVPHData.cpp
new file mode 100644
index 0000000..d617694
--- /dev/null
+++ b/hal/src/main/native/athena/mockdata/REVPHData.cpp
@@ -0,0 +1,37 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "hal/simulation/REVPHData.h"
+
+#include "hal/simulation/SimDataValue.h"
+
+extern "C" {
+void HALSIM_ResetREVPHData(int32_t index) {}
+
+#define DEFINE_CAPI(TYPE, CAPINAME, RETURN) \
+  HAL_SIMDATAVALUE_STUB_CAPI(TYPE, HALSIM, REVPH##CAPINAME, RETURN)
+
+HAL_SIMDATAVALUE_STUB_CAPI_CHANNEL(HAL_Bool, HALSIM, REVPHSolenoidOutput, false)
+DEFINE_CAPI(HAL_Bool, Initialized, false)
+DEFINE_CAPI(HAL_Bool, CompressorOn, false)
+DEFINE_CAPI(HAL_Bool, ClosedLoopEnabled, false)
+DEFINE_CAPI(HAL_Bool, PressureSwitch, false)
+DEFINE_CAPI(double, CompressorCurrent, 0)
+
+void HALSIM_GetREVPHAllSolenoids(int32_t index, uint8_t* values) {
+  *values = 0;
+}
+
+void HALSIM_SetREVPHAllSolenoids(int32_t index, uint8_t values) {}
+
+void HALSIM_RegisterREVPHAllNonSolenoidCallbacks(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify) {}
+
+void HALSIM_RegisterREVPHAllSolenoidCallbacks(int32_t index, int32_t channel,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify) {}
+}  // extern "C"
diff --git a/hal/src/main/native/athena/mockdata/RelayData.cpp b/hal/src/main/native/athena/mockdata/RelayData.cpp
index 734bf89..7d8d439 100644
--- a/hal/src/main/native/athena/mockdata/RelayData.cpp
+++ b/hal/src/main/native/athena/mockdata/RelayData.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/simulation/RelayData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/RoboRioData.cpp b/hal/src/main/native/athena/mockdata/RoboRioData.cpp
index f9e9ca7..9f6683a 100644
--- a/hal/src/main/native/athena/mockdata/RoboRioData.cpp
+++ b/hal/src/main/native/athena/mockdata/RoboRioData.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/simulation/RoboRioData.h"
 
@@ -30,6 +27,7 @@
 DEFINE_CAPI(int32_t, UserFaults6V, 0)
 DEFINE_CAPI(int32_t, UserFaults5V, 0)
 DEFINE_CAPI(int32_t, UserFaults3V3, 0)
+DEFINE_CAPI(double, BrownoutVoltage, 6.75)
 
 void HALSIM_RegisterRoboRioAllCallbacks(HAL_NotifyCallback callback,
                                         void* param, HAL_Bool initialNotify) {}
diff --git a/hal/src/main/native/athena/mockdata/SPIAccelerometerData.cpp b/hal/src/main/native/athena/mockdata/SPIAccelerometerData.cpp
index c3e8ede..c938abf 100644
--- a/hal/src/main/native/athena/mockdata/SPIAccelerometerData.cpp
+++ b/hal/src/main/native/athena/mockdata/SPIAccelerometerData.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/simulation/SPIAccelerometerData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/SPIData.cpp b/hal/src/main/native/athena/mockdata/SPIData.cpp
index 13cf67c..433ca10 100644
--- a/hal/src/main/native/athena/mockdata/SPIData.cpp
+++ b/hal/src/main/native/athena/mockdata/SPIData.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/simulation/SPIData.h"
 
diff --git a/hal/src/main/native/athena/mockdata/SimDeviceData.cpp b/hal/src/main/native/athena/mockdata/SimDeviceData.cpp
index a31160c..08bd8ce 100644
--- a/hal/src/main/native/athena/mockdata/SimDeviceData.cpp
+++ b/hal/src/main/native/athena/mockdata/SimDeviceData.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 "hal/simulation/SimDeviceData.h"
 
@@ -13,7 +10,9 @@
 
 void HALSIM_SetSimDeviceEnabled(const char* prefix, HAL_Bool enabled) {}
 
-HAL_Bool HALSIM_IsSimDeviceEnabled(const char* name) { return false; }
+HAL_Bool HALSIM_IsSimDeviceEnabled(const char* name) {
+  return false;
+}
 
 int32_t HALSIM_RegisterSimDeviceCreatedCallback(
     const char* prefix, void* param, HALSIM_SimDeviceCallback callback,
@@ -23,16 +22,21 @@
 
 void HALSIM_CancelSimDeviceCreatedCallback(int32_t 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 0;
 }
 
 void HALSIM_CancelSimDeviceFreedCallback(int32_t uid) {}
 
-HAL_SimDeviceHandle HALSIM_GetSimDeviceHandle(const char* name) { return 0; }
+HAL_SimDeviceHandle HALSIM_GetSimDeviceHandle(const char* name) {
+  return 0;
+}
 
-const char* HALSIM_GetSimDeviceName(HAL_SimDeviceHandle handle) { return ""; }
+const char* HALSIM_GetSimDeviceName(HAL_SimDeviceHandle handle) {
+  return "";
+}
 
 HAL_SimDeviceHandle HALSIM_GetSimValueDeviceHandle(HAL_SimValueHandle handle) {
   return 0;
@@ -59,6 +63,15 @@
 
 void HALSIM_CancelSimValueChangedCallback(int32_t uid) {}
 
+int32_t HALSIM_RegisterSimValueResetCallback(HAL_SimValueHandle handle,
+                                             void* param,
+                                             HALSIM_SimValueCallback callback,
+                                             HAL_Bool initialNotify) {
+  return 0;
+}
+
+void HALSIM_CancelSimValueResetCallback(int32_t uid) {}
+
 HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device,
                                             const char* name) {
   return 0;
@@ -73,6 +86,12 @@
   return nullptr;
 }
 
+const double* HALSIM_GetSimValueEnumDoubleValues(HAL_SimValueHandle handle,
+                                                 int32_t* numOptions) {
+  *numOptions = 0;
+  return nullptr;
+}
+
 void HALSIM_ResetSimDeviceData(void) {}
 
 }  // extern "C"
diff --git a/hal/src/main/native/athena/rev/PDHFrames.cpp b/hal/src/main/native/athena/rev/PDHFrames.cpp
new file mode 100644
index 0000000..b50a148
--- /dev/null
+++ b/hal/src/main/native/athena/rev/PDHFrames.cpp
@@ -0,0 +1,1790 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018-2019 Erik Moqvist
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * This file was generated by cantools version
+ */
+
+#include <string.h>
+
+#include "PDHFrames.h"
+
+static inline uint8_t pack_left_shift_u8(
+    uint8_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint8_t)((uint8_t)(value << shift) & mask);
+}
+
+static inline uint8_t pack_left_shift_u16(
+    uint16_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint8_t)((uint8_t)(value << shift) & mask);
+}
+
+static inline uint8_t pack_left_shift_u32(
+    uint32_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint8_t)((uint8_t)(value << shift) & mask);
+}
+
+static inline uint8_t pack_right_shift_u16(
+    uint16_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint8_t)((uint8_t)(value >> shift) & mask);
+}
+
+static inline uint8_t pack_right_shift_u32(
+    uint32_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint8_t)((uint8_t)(value >> shift) & mask);
+}
+
+static inline uint16_t unpack_left_shift_u16(
+    uint8_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint16_t)((uint16_t)(value & mask) << shift);
+}
+
+static inline uint32_t unpack_left_shift_u32(
+    uint8_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint32_t)((uint32_t)(value & mask) << shift);
+}
+
+static inline uint8_t unpack_right_shift_u8(
+    uint8_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint8_t)((uint8_t)(value & mask) >> shift);
+}
+
+static inline uint16_t unpack_right_shift_u16(
+    uint8_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint16_t)((uint16_t)(value & mask) >> shift);
+}
+
+static inline uint32_t unpack_right_shift_u32(
+    uint8_t value,
+    uint8_t shift,
+    uint8_t mask)
+{
+    return (uint32_t)((uint32_t)(value & mask) >> shift);
+}
+
+int PDH_switch_channel_set_pack(
+    uint8_t *dst_p,
+    const struct PDH_switch_channel_set_t *src_p,
+    size_t size)
+{
+    if (size < 1u) {
+        return (-EINVAL);
+    }
+
+    memset(&dst_p[0], 0, 1);
+
+    dst_p[0] |= pack_left_shift_u8(src_p->output_set_value, 0u, 0x01u);
+    dst_p[0] |= pack_left_shift_u8(src_p->use_system_enable, 1u, 0x02u);
+
+    return (1);
+}
+
+int PDH_switch_channel_set_unpack(
+    struct PDH_switch_channel_set_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    if (size < 1u) {
+        return (-EINVAL);
+    }
+
+    dst_p->output_set_value = unpack_right_shift_u8(src_p[0], 0u, 0x01u);
+    dst_p->use_system_enable = unpack_right_shift_u8(src_p[0], 1u, 0x02u);
+
+    return (0);
+}
+
+uint8_t PDH_switch_channel_set_output_set_value_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_switch_channel_set_output_set_value_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_switch_channel_set_output_set_value_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_switch_channel_set_use_system_enable_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_switch_channel_set_use_system_enable_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_switch_channel_set_use_system_enable_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+int PDH_status0_pack(
+    uint8_t *dst_p,
+    const struct PDH_status0_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    memset(&dst_p[0], 0, 8);
+
+    dst_p[0] |= pack_left_shift_u16(src_p->channel_0_current, 0u, 0xffu);
+    dst_p[1] |= pack_right_shift_u16(src_p->channel_0_current, 8u, 0x03u);
+    dst_p[1] |= pack_left_shift_u16(src_p->channel_1_current, 2u, 0xfcu);
+    dst_p[2] |= pack_right_shift_u16(src_p->channel_1_current, 6u, 0x0fu);
+    dst_p[2] |= pack_left_shift_u16(src_p->channel_2_current, 4u, 0xf0u);
+    dst_p[3] |= pack_right_shift_u16(src_p->channel_2_current, 4u, 0x3fu);
+    dst_p[3] |= pack_left_shift_u8(src_p->channel_0_brownout, 6u, 0x40u);
+    dst_p[3] |= pack_left_shift_u8(src_p->channel_1_brownout, 7u, 0x80u);
+    dst_p[4] |= pack_left_shift_u16(src_p->channel_3_current, 0u, 0xffu);
+    dst_p[5] |= pack_right_shift_u16(src_p->channel_3_current, 8u, 0x03u);
+    dst_p[5] |= pack_left_shift_u16(src_p->channel_4_current, 2u, 0xfcu);
+    dst_p[6] |= pack_right_shift_u16(src_p->channel_4_current, 6u, 0x0fu);
+    dst_p[6] |= pack_left_shift_u16(src_p->channel_5_current, 4u, 0xf0u);
+    dst_p[7] |= pack_right_shift_u16(src_p->channel_5_current, 4u, 0x3fu);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_2_brownout, 6u, 0x40u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_3_brownout, 7u, 0x80u);
+
+    return (8);
+}
+
+int PDH_status0_unpack(
+    struct PDH_status0_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    dst_p->channel_0_current = unpack_right_shift_u16(src_p[0], 0u, 0xffu);
+    dst_p->channel_0_current |= unpack_left_shift_u16(src_p[1], 8u, 0x03u);
+    dst_p->channel_1_current = unpack_right_shift_u16(src_p[1], 2u, 0xfcu);
+    dst_p->channel_1_current |= unpack_left_shift_u16(src_p[2], 6u, 0x0fu);
+    dst_p->channel_2_current = unpack_right_shift_u16(src_p[2], 4u, 0xf0u);
+    dst_p->channel_2_current |= unpack_left_shift_u16(src_p[3], 4u, 0x3fu);
+    dst_p->channel_0_brownout = unpack_right_shift_u8(src_p[3], 6u, 0x40u);
+    dst_p->channel_1_brownout = unpack_right_shift_u8(src_p[3], 7u, 0x80u);
+    dst_p->channel_3_current = unpack_right_shift_u16(src_p[4], 0u, 0xffu);
+    dst_p->channel_3_current |= unpack_left_shift_u16(src_p[5], 8u, 0x03u);
+    dst_p->channel_4_current = unpack_right_shift_u16(src_p[5], 2u, 0xfcu);
+    dst_p->channel_4_current |= unpack_left_shift_u16(src_p[6], 6u, 0x0fu);
+    dst_p->channel_5_current = unpack_right_shift_u16(src_p[6], 4u, 0xf0u);
+    dst_p->channel_5_current |= unpack_left_shift_u16(src_p[7], 4u, 0x3fu);
+    dst_p->channel_2_brownout = unpack_right_shift_u8(src_p[7], 6u, 0x40u);
+    dst_p->channel_3_brownout = unpack_right_shift_u8(src_p[7], 7u, 0x80u);
+
+    return (0);
+}
+
+uint16_t PDH_status0_channel_0_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status0_channel_0_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status0_channel_0_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status0_channel_1_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status0_channel_1_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status0_channel_1_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status0_channel_2_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status0_channel_2_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status0_channel_2_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint8_t PDH_status0_channel_0_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status0_channel_0_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status0_channel_0_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status0_channel_1_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status0_channel_1_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status0_channel_1_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint16_t PDH_status0_channel_3_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status0_channel_3_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status0_channel_3_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status0_channel_4_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status0_channel_4_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status0_channel_4_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status0_channel_5_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status0_channel_5_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status0_channel_5_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint8_t PDH_status0_channel_2_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status0_channel_2_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status0_channel_2_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status0_channel_3_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status0_channel_3_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status0_channel_3_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+int PDH_status1_pack(
+    uint8_t *dst_p,
+    const struct PDH_status1_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    memset(&dst_p[0], 0, 8);
+
+    dst_p[0] |= pack_left_shift_u16(src_p->channel_6_current, 0u, 0xffu);
+    dst_p[1] |= pack_right_shift_u16(src_p->channel_6_current, 8u, 0x03u);
+    dst_p[1] |= pack_left_shift_u16(src_p->channel_7_current, 2u, 0xfcu);
+    dst_p[2] |= pack_right_shift_u16(src_p->channel_7_current, 6u, 0x0fu);
+    dst_p[2] |= pack_left_shift_u16(src_p->channel_8_current, 4u, 0xf0u);
+    dst_p[3] |= pack_right_shift_u16(src_p->channel_8_current, 4u, 0x3fu);
+    dst_p[3] |= pack_left_shift_u8(src_p->channel_4_brownout, 6u, 0x40u);
+    dst_p[3] |= pack_left_shift_u8(src_p->channel_5_brownout, 7u, 0x80u);
+    dst_p[4] |= pack_left_shift_u16(src_p->channel_9_current, 0u, 0xffu);
+    dst_p[5] |= pack_right_shift_u16(src_p->channel_9_current, 8u, 0x03u);
+    dst_p[5] |= pack_left_shift_u16(src_p->channel_10_current, 2u, 0xfcu);
+    dst_p[6] |= pack_right_shift_u16(src_p->channel_10_current, 6u, 0x0fu);
+    dst_p[6] |= pack_left_shift_u16(src_p->channel_11_current, 4u, 0xf0u);
+    dst_p[7] |= pack_right_shift_u16(src_p->channel_11_current, 4u, 0x3fu);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_6_brownout, 6u, 0x40u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_7_brownout, 7u, 0x80u);
+
+    return (8);
+}
+
+int PDH_status1_unpack(
+    struct PDH_status1_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    dst_p->channel_6_current = unpack_right_shift_u16(src_p[0], 0u, 0xffu);
+    dst_p->channel_6_current |= unpack_left_shift_u16(src_p[1], 8u, 0x03u);
+    dst_p->channel_7_current = unpack_right_shift_u16(src_p[1], 2u, 0xfcu);
+    dst_p->channel_7_current |= unpack_left_shift_u16(src_p[2], 6u, 0x0fu);
+    dst_p->channel_8_current = unpack_right_shift_u16(src_p[2], 4u, 0xf0u);
+    dst_p->channel_8_current |= unpack_left_shift_u16(src_p[3], 4u, 0x3fu);
+    dst_p->channel_4_brownout = unpack_right_shift_u8(src_p[3], 6u, 0x40u);
+    dst_p->channel_5_brownout = unpack_right_shift_u8(src_p[3], 7u, 0x80u);
+    dst_p->channel_9_current = unpack_right_shift_u16(src_p[4], 0u, 0xffu);
+    dst_p->channel_9_current |= unpack_left_shift_u16(src_p[5], 8u, 0x03u);
+    dst_p->channel_10_current = unpack_right_shift_u16(src_p[5], 2u, 0xfcu);
+    dst_p->channel_10_current |= unpack_left_shift_u16(src_p[6], 6u, 0x0fu);
+    dst_p->channel_11_current = unpack_right_shift_u16(src_p[6], 4u, 0xf0u);
+    dst_p->channel_11_current |= unpack_left_shift_u16(src_p[7], 4u, 0x3fu);
+    dst_p->channel_6_brownout = unpack_right_shift_u8(src_p[7], 6u, 0x40u);
+    dst_p->channel_7_brownout = unpack_right_shift_u8(src_p[7], 7u, 0x80u);
+
+    return (0);
+}
+
+uint16_t PDH_status1_channel_6_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status1_channel_6_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status1_channel_6_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status1_channel_7_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status1_channel_7_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status1_channel_7_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status1_channel_8_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status1_channel_8_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status1_channel_8_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint8_t PDH_status1_channel_4_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status1_channel_4_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status1_channel_4_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status1_channel_5_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status1_channel_5_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status1_channel_5_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint16_t PDH_status1_channel_9_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status1_channel_9_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status1_channel_9_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status1_channel_10_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status1_channel_10_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status1_channel_10_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status1_channel_11_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status1_channel_11_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status1_channel_11_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint8_t PDH_status1_channel_6_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status1_channel_6_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status1_channel_6_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status1_channel_7_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status1_channel_7_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status1_channel_7_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+int PDH_status2_pack(
+    uint8_t *dst_p,
+    const struct PDH_status2_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    memset(&dst_p[0], 0, 8);
+
+    dst_p[0] |= pack_left_shift_u16(src_p->channel_12_current, 0u, 0xffu);
+    dst_p[1] |= pack_right_shift_u16(src_p->channel_12_current, 8u, 0x03u);
+    dst_p[1] |= pack_left_shift_u16(src_p->channel_13_current, 2u, 0xfcu);
+    dst_p[2] |= pack_right_shift_u16(src_p->channel_13_current, 6u, 0x0fu);
+    dst_p[2] |= pack_left_shift_u16(src_p->channel_14_current, 4u, 0xf0u);
+    dst_p[3] |= pack_right_shift_u16(src_p->channel_14_current, 4u, 0x3fu);
+    dst_p[3] |= pack_left_shift_u8(src_p->channel_8_brownout, 6u, 0x40u);
+    dst_p[3] |= pack_left_shift_u8(src_p->channel_9_brownout, 7u, 0x80u);
+    dst_p[4] |= pack_left_shift_u16(src_p->channel_15_current, 0u, 0xffu);
+    dst_p[5] |= pack_right_shift_u16(src_p->channel_15_current, 8u, 0x03u);
+    dst_p[5] |= pack_left_shift_u16(src_p->channel_16_current, 2u, 0xfcu);
+    dst_p[6] |= pack_right_shift_u16(src_p->channel_16_current, 6u, 0x0fu);
+    dst_p[6] |= pack_left_shift_u16(src_p->channel_17_current, 4u, 0xf0u);
+    dst_p[7] |= pack_right_shift_u16(src_p->channel_17_current, 4u, 0x3fu);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_10_brownout, 6u, 0x40u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_11_brownout, 7u, 0x80u);
+
+    return (8);
+}
+
+int PDH_status2_unpack(
+    struct PDH_status2_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    dst_p->channel_12_current = unpack_right_shift_u16(src_p[0], 0u, 0xffu);
+    dst_p->channel_12_current |= unpack_left_shift_u16(src_p[1], 8u, 0x03u);
+    dst_p->channel_13_current = unpack_right_shift_u16(src_p[1], 2u, 0xfcu);
+    dst_p->channel_13_current |= unpack_left_shift_u16(src_p[2], 6u, 0x0fu);
+    dst_p->channel_14_current = unpack_right_shift_u16(src_p[2], 4u, 0xf0u);
+    dst_p->channel_14_current |= unpack_left_shift_u16(src_p[3], 4u, 0x3fu);
+    dst_p->channel_8_brownout = unpack_right_shift_u8(src_p[3], 6u, 0x40u);
+    dst_p->channel_9_brownout = unpack_right_shift_u8(src_p[3], 7u, 0x80u);
+    dst_p->channel_15_current = unpack_right_shift_u16(src_p[4], 0u, 0xffu);
+    dst_p->channel_15_current |= unpack_left_shift_u16(src_p[5], 8u, 0x03u);
+    dst_p->channel_16_current = unpack_right_shift_u16(src_p[5], 2u, 0xfcu);
+    dst_p->channel_16_current |= unpack_left_shift_u16(src_p[6], 6u, 0x0fu);
+    dst_p->channel_17_current = unpack_right_shift_u16(src_p[6], 4u, 0xf0u);
+    dst_p->channel_17_current |= unpack_left_shift_u16(src_p[7], 4u, 0x3fu);
+    dst_p->channel_10_brownout = unpack_right_shift_u8(src_p[7], 6u, 0x40u);
+    dst_p->channel_11_brownout = unpack_right_shift_u8(src_p[7], 7u, 0x80u);
+
+    return (0);
+}
+
+uint16_t PDH_status2_channel_12_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status2_channel_12_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status2_channel_12_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status2_channel_13_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status2_channel_13_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status2_channel_13_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status2_channel_14_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status2_channel_14_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status2_channel_14_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint8_t PDH_status2_channel_8_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status2_channel_8_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status2_channel_8_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status2_channel_9_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status2_channel_9_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status2_channel_9_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint16_t PDH_status2_channel_15_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status2_channel_15_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status2_channel_15_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status2_channel_16_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status2_channel_16_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status2_channel_16_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status2_channel_17_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status2_channel_17_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status2_channel_17_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint8_t PDH_status2_channel_10_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status2_channel_10_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status2_channel_10_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status2_channel_11_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status2_channel_11_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status2_channel_11_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+int PDH_status3_pack(
+    uint8_t *dst_p,
+    const struct PDH_status3_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    memset(&dst_p[0], 0, 8);
+
+    dst_p[0] |= pack_left_shift_u16(src_p->channel_18_current, 0u, 0xffu);
+    dst_p[1] |= pack_right_shift_u16(src_p->channel_18_current, 8u, 0x03u);
+    dst_p[1] |= pack_left_shift_u16(src_p->channel_19_current, 2u, 0xfcu);
+    dst_p[2] |= pack_right_shift_u16(src_p->channel_19_current, 6u, 0x0fu);
+    dst_p[2] |= pack_left_shift_u8(src_p->channel_12_brownout, 4u, 0x10u);
+    dst_p[2] |= pack_left_shift_u8(src_p->channel_13_brownout, 5u, 0x20u);
+    dst_p[2] |= pack_left_shift_u8(src_p->channel_14_brownout, 6u, 0x40u);
+    dst_p[2] |= pack_left_shift_u8(src_p->channel_15_brownout, 7u, 0x80u);
+    dst_p[3] |= pack_left_shift_u8(src_p->channel_20_current, 0u, 0xffu);
+    dst_p[4] |= pack_left_shift_u8(src_p->channel_21_current, 0u, 0xffu);
+    dst_p[5] |= pack_left_shift_u8(src_p->channel_22_current, 0u, 0xffu);
+    dst_p[6] |= pack_left_shift_u8(src_p->channel_23_current, 0u, 0xffu);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_16_brownout, 0u, 0x01u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_17_brownout, 1u, 0x02u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_18_brownout, 2u, 0x04u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_19_brownout, 3u, 0x08u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_20_brownout, 4u, 0x10u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_21_brownout, 5u, 0x20u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_22_brownout, 6u, 0x40u);
+    dst_p[7] |= pack_left_shift_u8(src_p->channel_23_brownout, 7u, 0x80u);
+
+    return (8);
+}
+
+int PDH_status3_unpack(
+    struct PDH_status3_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    dst_p->channel_18_current = unpack_right_shift_u16(src_p[0], 0u, 0xffu);
+    dst_p->channel_18_current |= unpack_left_shift_u16(src_p[1], 8u, 0x03u);
+    dst_p->channel_19_current = unpack_right_shift_u16(src_p[1], 2u, 0xfcu);
+    dst_p->channel_19_current |= unpack_left_shift_u16(src_p[2], 6u, 0x0fu);
+    dst_p->channel_12_brownout = unpack_right_shift_u8(src_p[2], 4u, 0x10u);
+    dst_p->channel_13_brownout = unpack_right_shift_u8(src_p[2], 5u, 0x20u);
+    dst_p->channel_14_brownout = unpack_right_shift_u8(src_p[2], 6u, 0x40u);
+    dst_p->channel_15_brownout = unpack_right_shift_u8(src_p[2], 7u, 0x80u);
+    dst_p->channel_20_current = unpack_right_shift_u8(src_p[3], 0u, 0xffu);
+    dst_p->channel_21_current = unpack_right_shift_u8(src_p[4], 0u, 0xffu);
+    dst_p->channel_22_current = unpack_right_shift_u8(src_p[5], 0u, 0xffu);
+    dst_p->channel_23_current = unpack_right_shift_u8(src_p[6], 0u, 0xffu);
+    dst_p->channel_16_brownout = unpack_right_shift_u8(src_p[7], 0u, 0x01u);
+    dst_p->channel_17_brownout = unpack_right_shift_u8(src_p[7], 1u, 0x02u);
+    dst_p->channel_18_brownout = unpack_right_shift_u8(src_p[7], 2u, 0x04u);
+    dst_p->channel_19_brownout = unpack_right_shift_u8(src_p[7], 3u, 0x08u);
+    dst_p->channel_20_brownout = unpack_right_shift_u8(src_p[7], 4u, 0x10u);
+    dst_p->channel_21_brownout = unpack_right_shift_u8(src_p[7], 5u, 0x20u);
+    dst_p->channel_22_brownout = unpack_right_shift_u8(src_p[7], 6u, 0x40u);
+    dst_p->channel_23_brownout = unpack_right_shift_u8(src_p[7], 7u, 0x80u);
+
+    return (0);
+}
+
+uint16_t PDH_status3_channel_18_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status3_channel_18_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status3_channel_18_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint16_t PDH_status3_channel_19_current_encode(double value)
+{
+    return (uint16_t)(value / 0.125);
+}
+
+double PDH_status3_channel_19_current_decode(uint16_t value)
+{
+    return ((double)value * 0.125);
+}
+
+bool PDH_status3_channel_19_current_is_in_range(uint16_t value)
+{
+    return (value <= 1023u);
+}
+
+uint8_t PDH_status3_channel_12_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_12_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_12_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_13_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_13_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_13_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_14_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_14_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_14_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_15_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_15_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_15_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_20_current_encode(double value)
+{
+    return (uint8_t)(value / 0.0625);
+}
+
+double PDH_status3_channel_20_current_decode(uint8_t value)
+{
+    return ((double)value * 0.0625);
+}
+
+bool PDH_status3_channel_20_current_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+uint8_t PDH_status3_channel_21_current_encode(double value)
+{
+    return (uint8_t)(value / 0.0625);
+}
+
+double PDH_status3_channel_21_current_decode(uint8_t value)
+{
+    return ((double)value * 0.0625);
+}
+
+bool PDH_status3_channel_21_current_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+uint8_t PDH_status3_channel_22_current_encode(double value)
+{
+    return (uint8_t)(value / 0.0625);
+}
+
+double PDH_status3_channel_22_current_decode(uint8_t value)
+{
+    return ((double)value * 0.0625);
+}
+
+bool PDH_status3_channel_22_current_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+uint8_t PDH_status3_channel_23_current_encode(double value)
+{
+    return (uint8_t)(value / 0.0625);
+}
+
+double PDH_status3_channel_23_current_decode(uint8_t value)
+{
+    return ((double)value * 0.0625);
+}
+
+bool PDH_status3_channel_23_current_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+uint8_t PDH_status3_channel_16_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_16_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_16_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_17_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_17_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_17_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_18_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_18_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_18_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_19_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_19_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_19_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_20_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_20_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_20_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_21_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_21_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_21_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_22_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_22_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_22_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status3_channel_23_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status3_channel_23_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status3_channel_23_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+int PDH_status4_pack(
+    uint8_t *dst_p,
+    const struct PDH_status4_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    memset(&dst_p[0], 0, 8);
+
+    dst_p[0] |= pack_left_shift_u16(src_p->v_bus, 0u, 0xffu);
+    dst_p[1] |= pack_right_shift_u16(src_p->v_bus, 8u, 0x0fu);
+    dst_p[1] |= pack_left_shift_u8(src_p->system_enable, 4u, 0x10u);
+    dst_p[1] |= pack_left_shift_u8(src_p->rsvd0, 5u, 0xe0u);
+    dst_p[2] |= pack_left_shift_u8(src_p->brownout, 0u, 0x01u);
+    dst_p[2] |= pack_left_shift_u8(src_p->rsvd1, 1u, 0x02u);
+    dst_p[2] |= pack_left_shift_u8(src_p->can_warning, 2u, 0x04u);
+    dst_p[2] |= pack_left_shift_u8(src_p->hardware_fault, 3u, 0x08u);
+    dst_p[2] |= pack_left_shift_u8(src_p->sw_state, 4u, 0x10u);
+    dst_p[2] |= pack_left_shift_u8(src_p->sticky_brownout, 5u, 0x20u);
+    dst_p[2] |= pack_left_shift_u8(src_p->rsvd2, 6u, 0x40u);
+    dst_p[2] |= pack_left_shift_u8(src_p->sticky_can_warning, 7u, 0x80u);
+    dst_p[3] |= pack_left_shift_u8(src_p->sticky_can_bus_off, 0u, 0x01u);
+    dst_p[3] |= pack_left_shift_u8(src_p->sticky_hardware_fault, 1u, 0x02u);
+    dst_p[3] |= pack_left_shift_u8(src_p->sticky_firmware_fault, 2u, 0x04u);
+    dst_p[3] |= pack_left_shift_u8(src_p->sticky_ch20_brownout, 3u, 0x08u);
+    dst_p[3] |= pack_left_shift_u8(src_p->sticky_ch21_brownout, 4u, 0x10u);
+    dst_p[3] |= pack_left_shift_u8(src_p->sticky_ch22_brownout, 5u, 0x20u);
+    dst_p[3] |= pack_left_shift_u8(src_p->sticky_ch23_brownout, 6u, 0x40u);
+    dst_p[3] |= pack_left_shift_u8(src_p->sticky_has_reset, 7u, 0x80u);
+    dst_p[4] |= pack_left_shift_u8(src_p->total_current, 0u, 0xffu);
+
+    return (8);
+}
+
+int PDH_status4_unpack(
+    struct PDH_status4_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    dst_p->v_bus = unpack_right_shift_u16(src_p[0], 0u, 0xffu);
+    dst_p->v_bus |= unpack_left_shift_u16(src_p[1], 8u, 0x0fu);
+    dst_p->system_enable = unpack_right_shift_u8(src_p[1], 4u, 0x10u);
+    dst_p->rsvd0 = unpack_right_shift_u8(src_p[1], 5u, 0xe0u);
+    dst_p->brownout = unpack_right_shift_u8(src_p[2], 0u, 0x01u);
+    dst_p->rsvd1 = unpack_right_shift_u8(src_p[2], 1u, 0x02u);
+    dst_p->can_warning = unpack_right_shift_u8(src_p[2], 2u, 0x04u);
+    dst_p->hardware_fault = unpack_right_shift_u8(src_p[2], 3u, 0x08u);
+    dst_p->sw_state = unpack_right_shift_u8(src_p[2], 4u, 0x10u);
+    dst_p->sticky_brownout = unpack_right_shift_u8(src_p[2], 5u, 0x20u);
+    dst_p->rsvd2 = unpack_right_shift_u8(src_p[2], 6u, 0x40u);
+    dst_p->sticky_can_warning = unpack_right_shift_u8(src_p[2], 7u, 0x80u);
+    dst_p->sticky_can_bus_off = unpack_right_shift_u8(src_p[3], 0u, 0x01u);
+    dst_p->sticky_hardware_fault = unpack_right_shift_u8(src_p[3], 1u, 0x02u);
+    dst_p->sticky_firmware_fault = unpack_right_shift_u8(src_p[3], 2u, 0x04u);
+    dst_p->sticky_ch20_brownout = unpack_right_shift_u8(src_p[3], 3u, 0x08u);
+    dst_p->sticky_ch21_brownout = unpack_right_shift_u8(src_p[3], 4u, 0x10u);
+    dst_p->sticky_ch22_brownout = unpack_right_shift_u8(src_p[3], 5u, 0x20u);
+    dst_p->sticky_ch23_brownout = unpack_right_shift_u8(src_p[3], 6u, 0x40u);
+    dst_p->sticky_has_reset = unpack_right_shift_u8(src_p[3], 7u, 0x80u);
+    dst_p->total_current = unpack_right_shift_u8(src_p[4], 0u, 0xffu);
+
+    return (0);
+}
+
+uint16_t PDH_status4_v_bus_encode(double value)
+{
+    return (uint16_t)(value / 0.0078125);
+}
+
+double PDH_status4_v_bus_decode(uint16_t value)
+{
+    return ((double)value * 0.0078125);
+}
+
+bool PDH_status4_v_bus_is_in_range(uint16_t value)
+{
+    return (value <= 4095u);
+}
+
+uint8_t PDH_status4_system_enable_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_system_enable_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_system_enable_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_rsvd0_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_rsvd0_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_rsvd0_is_in_range(uint8_t value)
+{
+    return (value <= 7u);
+}
+
+uint8_t PDH_status4_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_rsvd1_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_rsvd1_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_rsvd1_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_can_warning_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_can_warning_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_can_warning_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_hardware_fault_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_hardware_fault_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_hardware_fault_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sw_state_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sw_state_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sw_state_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_rsvd2_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_rsvd2_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_rsvd2_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_can_warning_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_can_warning_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_can_warning_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_can_bus_off_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_can_bus_off_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_can_bus_off_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_hardware_fault_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_hardware_fault_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_hardware_fault_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_firmware_fault_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_firmware_fault_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_firmware_fault_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_ch20_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_ch20_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_ch20_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_ch21_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_ch21_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_ch21_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_ch22_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_ch22_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_ch22_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_ch23_brownout_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_ch23_brownout_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_ch23_brownout_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_sticky_has_reset_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_status4_sticky_has_reset_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_status4_sticky_has_reset_is_in_range(uint8_t value)
+{
+    return (value <= 1u);
+}
+
+uint8_t PDH_status4_total_current_encode(double value)
+{
+    return (uint8_t)(value / 2.0);
+}
+
+double PDH_status4_total_current_decode(uint8_t value)
+{
+    return ((double)value * 2.0);
+}
+
+bool PDH_status4_total_current_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+int PDH_clear_faults_pack(
+    uint8_t *dst_p,
+    const struct PDH_clear_faults_t *src_p,
+    size_t size)
+{
+    (void)dst_p;
+    (void)src_p;
+    (void)size;
+
+    return (0);
+}
+
+int PDH_clear_faults_unpack(
+    struct PDH_clear_faults_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    (void)dst_p;
+    (void)src_p;
+    (void)size;
+
+    return (0);
+}
+
+int PDH_identify_pack(
+    uint8_t *dst_p,
+    const struct PDH_identify_t *src_p,
+    size_t size)
+{
+    (void)dst_p;
+    (void)src_p;
+    (void)size;
+
+    return (0);
+}
+
+int PDH_identify_unpack(
+    struct PDH_identify_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    (void)dst_p;
+    (void)src_p;
+    (void)size;
+
+    return (0);
+}
+
+int PDH_version_pack(
+    uint8_t *dst_p,
+    const struct PDH_version_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    memset(&dst_p[0], 0, 8);
+
+    dst_p[0] |= pack_left_shift_u8(src_p->firmware_fix, 0u, 0xffu);
+    dst_p[1] |= pack_left_shift_u8(src_p->firmware_minor, 0u, 0xffu);
+    dst_p[2] |= pack_left_shift_u8(src_p->firmware_year, 0u, 0xffu);
+    dst_p[3] |= pack_left_shift_u8(src_p->hardware_code, 0u, 0xffu);
+    dst_p[4] |= pack_left_shift_u32(src_p->unique_id, 0u, 0xffu);
+    dst_p[5] |= pack_right_shift_u32(src_p->unique_id, 8u, 0xffu);
+    dst_p[6] |= pack_right_shift_u32(src_p->unique_id, 16u, 0xffu);
+    dst_p[7] |= pack_right_shift_u32(src_p->unique_id, 24u, 0xffu);
+
+    return (8);
+}
+
+int PDH_version_unpack(
+    struct PDH_version_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    if (size < 8u) {
+        return (-EINVAL);
+    }
+
+    dst_p->firmware_fix = unpack_right_shift_u8(src_p[0], 0u, 0xffu);
+    dst_p->firmware_minor = unpack_right_shift_u8(src_p[1], 0u, 0xffu);
+    dst_p->firmware_year = unpack_right_shift_u8(src_p[2], 0u, 0xffu);
+    dst_p->hardware_code = unpack_right_shift_u8(src_p[3], 0u, 0xffu);
+    dst_p->unique_id = unpack_right_shift_u32(src_p[4], 0u, 0xffu);
+    dst_p->unique_id |= unpack_left_shift_u32(src_p[5], 8u, 0xffu);
+    dst_p->unique_id |= unpack_left_shift_u32(src_p[6], 16u, 0xffu);
+    dst_p->unique_id |= unpack_left_shift_u32(src_p[7], 24u, 0xffu);
+
+    return (0);
+}
+
+uint8_t PDH_version_firmware_fix_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_version_firmware_fix_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_version_firmware_fix_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+uint8_t PDH_version_firmware_minor_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_version_firmware_minor_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_version_firmware_minor_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+uint8_t PDH_version_firmware_year_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_version_firmware_year_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_version_firmware_year_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+uint8_t PDH_version_hardware_code_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_version_hardware_code_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_version_hardware_code_is_in_range(uint8_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+uint32_t PDH_version_unique_id_encode(double value)
+{
+    return (uint32_t)(value);
+}
+
+double PDH_version_unique_id_decode(uint32_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_version_unique_id_is_in_range(uint32_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+int PDH_configure_hr_channel_pack(
+    uint8_t *dst_p,
+    const struct PDH_configure_hr_channel_t *src_p,
+    size_t size)
+{
+    if (size < 3u) {
+        return (-EINVAL);
+    }
+
+    memset(&dst_p[0], 0, 3);
+
+    dst_p[0] |= pack_left_shift_u8(src_p->channel, 0u, 0xffu);
+    dst_p[1] |= pack_left_shift_u16(src_p->period, 0u, 0xffu);
+    dst_p[2] |= pack_right_shift_u16(src_p->period, 8u, 0xffu);
+
+    return (3);
+}
+
+int PDH_configure_hr_channel_unpack(
+    struct PDH_configure_hr_channel_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    if (size < 3u) {
+        return (-EINVAL);
+    }
+
+    dst_p->channel = unpack_right_shift_u8(src_p[0], 0u, 0xffu);
+    dst_p->period = unpack_right_shift_u16(src_p[1], 0u, 0xffu);
+    dst_p->period |= unpack_left_shift_u16(src_p[2], 8u, 0xffu);
+
+    return (0);
+}
+
+uint8_t PDH_configure_hr_channel_channel_encode(double value)
+{
+    return (uint8_t)(value);
+}
+
+double PDH_configure_hr_channel_channel_decode(uint8_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_configure_hr_channel_channel_is_in_range(uint8_t value)
+{
+    return (value <= 23u);
+}
+
+uint16_t PDH_configure_hr_channel_period_encode(double value)
+{
+    return (uint16_t)(value);
+}
+
+double PDH_configure_hr_channel_period_decode(uint16_t value)
+{
+    return ((double)value);
+}
+
+bool PDH_configure_hr_channel_period_is_in_range(uint16_t value)
+{
+    (void)value;
+
+    return (true);
+}
+
+int PDH_enter_bootloader_pack(
+    uint8_t *dst_p,
+    const struct PDH_enter_bootloader_t *src_p,
+    size_t size)
+{
+    (void)dst_p;
+    (void)src_p;
+    (void)size;
+
+    return (0);
+}
+
+int PDH_enter_bootloader_unpack(
+    struct PDH_enter_bootloader_t *dst_p,
+    const uint8_t *src_p,
+    size_t size)
+{
+    (void)dst_p;
+    (void)src_p;
+    (void)size;
+
+    return (0);
+}
diff --git a/hal/src/main/native/athena/rev/PDHFrames.h b/hal/src/main/native/athena/rev/PDHFrames.h
new file mode 100644
index 0000000..5d2452a
--- /dev/null
+++ b/hal/src/main/native/athena/rev/PDHFrames.h
@@ -0,0 +1,3136 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018-2019 Erik Moqvist
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * This file was generated by cantools version
+ */
+
+#ifndef PDH_H
+#define PDH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifndef EINVAL
+#    define EINVAL 22
+#endif
+
+/* Frame ids. */
+#define PDH_SWITCH_CHANNEL_SET_FRAME_ID (0x8050840u)
+#define PDH_STATUS0_FRAME_ID (0x8051800u)
+#define PDH_STATUS1_FRAME_ID (0x8051840u)
+#define PDH_STATUS2_FRAME_ID (0x8051880u)
+#define PDH_STATUS3_FRAME_ID (0x80518c0u)
+#define PDH_STATUS4_FRAME_ID (0x8051900u)
+#define PDH_CLEAR_FAULTS_FRAME_ID (0x8051b80u)
+#define PDH_IDENTIFY_FRAME_ID (0x8051d80u)
+#define PDH_VERSION_FRAME_ID (0x8052600u)
+#define PDH_CONFIGURE_HR_CHANNEL_FRAME_ID (0x80538c0u)
+#define PDH_ENTER_BOOTLOADER_FRAME_ID (0x8057fc0u)
+
+/* Frame lengths in bytes. */
+#define PDH_SWITCH_CHANNEL_SET_LENGTH (1u)
+#define PDH_STATUS0_LENGTH (8u)
+#define PDH_STATUS1_LENGTH (8u)
+#define PDH_STATUS2_LENGTH (8u)
+#define PDH_STATUS3_LENGTH (8u)
+#define PDH_STATUS4_LENGTH (8u)
+#define PDH_CLEAR_FAULTS_LENGTH (0u)
+#define PDH_IDENTIFY_LENGTH (0u)
+#define PDH_VERSION_LENGTH (8u)
+#define PDH_CONFIGURE_HR_CHANNEL_LENGTH (3u)
+#define PDH_ENTER_BOOTLOADER_LENGTH (0u)
+
+/* Extended or standard frame types. */
+#define PDH_SWITCH_CHANNEL_SET_IS_EXTENDED (1)
+#define PDH_STATUS0_IS_EXTENDED (1)
+#define PDH_STATUS1_IS_EXTENDED (1)
+#define PDH_STATUS2_IS_EXTENDED (1)
+#define PDH_STATUS3_IS_EXTENDED (1)
+#define PDH_STATUS4_IS_EXTENDED (1)
+#define PDH_CLEAR_FAULTS_IS_EXTENDED (1)
+#define PDH_IDENTIFY_IS_EXTENDED (1)
+#define PDH_VERSION_IS_EXTENDED (1)
+#define PDH_CONFIGURE_HR_CHANNEL_IS_EXTENDED (1)
+#define PDH_ENTER_BOOTLOADER_IS_EXTENDED (1)
+
+/* Frame cycle times in milliseconds. */
+
+
+/* Signal choices. */
+
+
+/**
+ * Signals in message SwitchChannelSet.
+ *
+ * Set the switch channel output
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_switch_channel_set_t {
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t output_set_value : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t use_system_enable : 1;
+};
+
+/**
+ * Signals in message Status0.
+ *
+ * Periodic status frame 0
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_status0_t {
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_0_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_1_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_2_current : 10;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_0_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_1_brownout : 1;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_3_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_4_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_5_current : 10;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_2_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_3_brownout : 1;
+};
+
+/**
+ * Signals in message Status1.
+ *
+ * Periodic status frame 1
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_status1_t {
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_6_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_7_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_8_current : 10;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_4_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_5_brownout : 1;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_9_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_10_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_11_current : 10;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_6_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_7_brownout : 1;
+};
+
+/**
+ * Signals in message Status2.
+ *
+ * Periodic status frame 2
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_status2_t {
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_12_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_13_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_14_current : 10;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_8_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_9_brownout : 1;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_15_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_16_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_17_current : 10;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_10_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_11_brownout : 1;
+};
+
+/**
+ * Signals in message Status3.
+ *
+ * Periodic status frame 3
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_status3_t {
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_18_current : 10;
+
+    /**
+     * Range: 0..1023 (0..127.875 A)
+     * Scale: 0.125
+     * Offset: 0
+     */
+    uint16_t channel_19_current : 10;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_12_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_13_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_14_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_15_brownout : 1;
+
+    /**
+     * Range: 0..255 (0..15.9375 A)
+     * Scale: 0.0625
+     * Offset: 0
+     */
+    uint8_t channel_20_current : 8;
+
+    /**
+     * Range: 0..255 (0..15.9375 A)
+     * Scale: 0.0625
+     * Offset: 0
+     */
+    uint8_t channel_21_current : 8;
+
+    /**
+     * Range: 0..511 (0..31.9375 A)
+     * Scale: 0.0625
+     * Offset: 0
+     */
+    uint8_t channel_22_current : 8;
+
+    /**
+     * Range: 0..511 (0..31.9375 A)
+     * Scale: 0.0625
+     * Offset: 0
+     */
+    uint8_t channel_23_current : 8;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_16_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_17_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_18_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_19_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_20_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_21_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_22_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel_23_brownout : 1;
+};
+
+/**
+ * Signals in message Status4.
+ *
+ * Periodic status frame 4
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_status4_t {
+    /**
+     * Range: 0..4095 (0..31.9921875 V)
+     * Scale: 0.0078125
+     * Offset: 0
+     */
+    uint16_t v_bus : 12;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t system_enable : 1;
+
+    /**
+     * Range: 0..7 (0..7 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t rsvd0 : 3;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t rsvd1 : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t can_warning : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t hardware_fault : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sw_state : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t rsvd2 : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_can_warning : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_can_bus_off : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_hardware_fault : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_firmware_fault : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_ch20_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_ch21_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_ch22_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_ch23_brownout : 1;
+
+    /**
+     * Range: 0..1 (0..1 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t sticky_has_reset : 1;
+
+    /**
+     * Range: 0..255 (0..510 A)
+     * Scale: 2
+     * Offset: 0
+     */
+    uint8_t total_current : 8;
+};
+
+/**
+ * Signals in message ClearFaults.
+ *
+ * Clear sticky faults on the device
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_clear_faults_t {
+    /**
+     * Dummy signal in empty message.
+     */
+    uint8_t dummy;
+};
+
+/**
+ * Signals in message Identify.
+ *
+ * Flash the LED on the device to identify this device
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_identify_t {
+    /**
+     * Dummy signal in empty message.
+     */
+    uint8_t dummy;
+};
+
+/**
+ * Signals in message Version.
+ *
+ * Get the version of the PDH device
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_version_t {
+    /**
+     * Range: 0..255 (0..255 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t firmware_fix : 8;
+
+    /**
+     * Range: 0..255 (0..255 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t firmware_minor : 8;
+
+    /**
+     * Range: 0..255 (0..255 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t firmware_year : 8;
+
+    /**
+     * Range: 0..255 (0..255 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t hardware_code : 8;
+
+    /**
+     * Range: 0..4294967295 (0..4294967295 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint32_t unique_id : 32;
+};
+
+/**
+ * Signals in message ConfigureHRChannel.
+ *
+ * Configure a periodic high-resolution channel frame to send back data for a particular channel. This can be useful for more detailed diagnostics, or even for current based control or monitoring.
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_configure_hr_channel_t {
+    /**
+     * Range: 0..23 (0..23 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint8_t channel : 8;
+
+    /**
+     * Range: 0..65535 (0..65535 -)
+     * Scale: 1
+     * Offset: 0
+     */
+    uint16_t period : 16;
+};
+
+/**
+ * Signals in message Enter_Bootloader.
+ *
+ * Enter the REV bootloader from user application
+ *
+ * All signal values are as on the CAN bus.
+ */
+struct PDH_enter_bootloader_t {
+    /**
+     * Dummy signal in empty message.
+     */
+    uint8_t dummy;
+};
+
+/**
+ * Pack message SwitchChannelSet.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_switch_channel_set_pack(
+    uint8_t *dst_p,
+    const struct PDH_switch_channel_set_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message SwitchChannelSet.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_switch_channel_set_unpack(
+    struct PDH_switch_channel_set_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_switch_channel_set_output_set_value_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_switch_channel_set_output_set_value_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_switch_channel_set_output_set_value_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_switch_channel_set_use_system_enable_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_switch_channel_set_use_system_enable_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_switch_channel_set_use_system_enable_is_in_range(uint8_t value);
+
+/**
+ * Pack message Status0.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_status0_pack(
+    uint8_t *dst_p,
+    const struct PDH_status0_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message Status0.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_status0_unpack(
+    struct PDH_status0_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status0_channel_0_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_0_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_0_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status0_channel_1_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_1_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_1_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status0_channel_2_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_2_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_2_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status0_channel_0_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_0_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_0_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status0_channel_1_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_1_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_1_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status0_channel_3_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_3_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_3_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status0_channel_4_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_4_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_4_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status0_channel_5_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_5_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_5_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status0_channel_2_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_2_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_2_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status0_channel_3_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status0_channel_3_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status0_channel_3_brownout_is_in_range(uint8_t value);
+
+/**
+ * Pack message Status1.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_status1_pack(
+    uint8_t *dst_p,
+    const struct PDH_status1_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message Status1.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_status1_unpack(
+    struct PDH_status1_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status1_channel_6_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_6_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_6_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status1_channel_7_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_7_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_7_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status1_channel_8_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_8_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_8_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status1_channel_4_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_4_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_4_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status1_channel_5_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_5_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_5_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status1_channel_9_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_9_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_9_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status1_channel_10_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_10_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_10_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status1_channel_11_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_11_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_11_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status1_channel_6_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_6_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_6_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status1_channel_7_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status1_channel_7_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status1_channel_7_brownout_is_in_range(uint8_t value);
+
+/**
+ * Pack message Status2.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_status2_pack(
+    uint8_t *dst_p,
+    const struct PDH_status2_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message Status2.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_status2_unpack(
+    struct PDH_status2_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status2_channel_12_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_12_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_12_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status2_channel_13_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_13_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_13_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status2_channel_14_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_14_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_14_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status2_channel_8_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_8_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_8_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status2_channel_9_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_9_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_9_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status2_channel_15_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_15_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_15_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status2_channel_16_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_16_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_16_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status2_channel_17_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_17_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_17_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status2_channel_10_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_10_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_10_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status2_channel_11_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status2_channel_11_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status2_channel_11_brownout_is_in_range(uint8_t value);
+
+/**
+ * Pack message Status3.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_status3_pack(
+    uint8_t *dst_p,
+    const struct PDH_status3_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message Status3.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_status3_unpack(
+    struct PDH_status3_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status3_channel_18_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_18_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_18_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status3_channel_19_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_19_current_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_19_current_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_12_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_12_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_12_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_13_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_13_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_13_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_14_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_14_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_14_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_15_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_15_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_15_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_20_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_20_current_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_20_current_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_21_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_21_current_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_21_current_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_22_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_22_current_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_22_current_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_23_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_23_current_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_23_current_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_16_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_16_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_16_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_17_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_17_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_17_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_18_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_18_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_18_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_19_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_19_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_19_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_20_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_20_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_20_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_21_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_21_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_21_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_22_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_22_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_22_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status3_channel_23_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status3_channel_23_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status3_channel_23_brownout_is_in_range(uint8_t value);
+
+/**
+ * Pack message Status4.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_status4_pack(
+    uint8_t *dst_p,
+    const struct PDH_status4_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message Status4.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_status4_unpack(
+    struct PDH_status4_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_status4_v_bus_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_v_bus_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_v_bus_is_in_range(uint16_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_system_enable_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_system_enable_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_system_enable_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_rsvd0_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_rsvd0_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_rsvd0_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_rsvd1_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_rsvd1_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_rsvd1_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_can_warning_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_can_warning_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_can_warning_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_hardware_fault_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_hardware_fault_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_hardware_fault_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sw_state_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sw_state_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sw_state_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_rsvd2_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_rsvd2_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_rsvd2_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_can_warning_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_can_warning_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_can_warning_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_can_bus_off_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_can_bus_off_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_can_bus_off_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_hardware_fault_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_hardware_fault_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_hardware_fault_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_firmware_fault_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_firmware_fault_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_firmware_fault_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_ch20_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_ch20_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_ch20_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_ch21_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_ch21_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_ch21_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_ch22_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_ch22_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_ch22_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_ch23_brownout_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_ch23_brownout_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_ch23_brownout_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_sticky_has_reset_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_sticky_has_reset_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_sticky_has_reset_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_status4_total_current_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_status4_total_current_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_status4_total_current_is_in_range(uint8_t value);
+
+/**
+ * Pack message ClearFaults.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_clear_faults_pack(
+    uint8_t *dst_p,
+    const struct PDH_clear_faults_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message ClearFaults.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_clear_faults_unpack(
+    struct PDH_clear_faults_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Pack message Identify.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_identify_pack(
+    uint8_t *dst_p,
+    const struct PDH_identify_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message Identify.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_identify_unpack(
+    struct PDH_identify_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Pack message Version.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_version_pack(
+    uint8_t *dst_p,
+    const struct PDH_version_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message Version.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_version_unpack(
+    struct PDH_version_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_version_firmware_fix_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_version_firmware_fix_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_version_firmware_fix_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_version_firmware_minor_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_version_firmware_minor_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_version_firmware_minor_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_version_firmware_year_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_version_firmware_year_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_version_firmware_year_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_version_hardware_code_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_version_hardware_code_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_version_hardware_code_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint32_t PDH_version_unique_id_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_version_unique_id_decode(uint32_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_version_unique_id_is_in_range(uint32_t value);
+
+/**
+ * Pack message ConfigureHRChannel.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_configure_hr_channel_pack(
+    uint8_t *dst_p,
+    const struct PDH_configure_hr_channel_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message ConfigureHRChannel.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_configure_hr_channel_unpack(
+    struct PDH_configure_hr_channel_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint8_t PDH_configure_hr_channel_channel_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_configure_hr_channel_channel_decode(uint8_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_configure_hr_channel_channel_is_in_range(uint8_t value);
+
+/**
+ * Encode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to encode.
+ *
+ * @return Encoded signal.
+ */
+uint16_t PDH_configure_hr_channel_period_encode(double value);
+
+/**
+ * Decode given signal by applying scaling and offset.
+ *
+ * @param[in] value Signal to decode.
+ *
+ * @return Decoded signal.
+ */
+double PDH_configure_hr_channel_period_decode(uint16_t value);
+
+/**
+ * Check that given signal is in allowed range.
+ *
+ * @param[in] value Signal to check.
+ *
+ * @return true if in range, false otherwise.
+ */
+bool PDH_configure_hr_channel_period_is_in_range(uint16_t value);
+
+/**
+ * Pack message Enter_Bootloader.
+ *
+ * @param[out] dst_p Buffer to pack the message into.
+ * @param[in] src_p Data to pack.
+ * @param[in] size Size of dst_p.
+ *
+ * @return Size of packed data, or negative error code.
+ */
+int PDH_enter_bootloader_pack(
+    uint8_t *dst_p,
+    const struct PDH_enter_bootloader_t *src_p,
+    size_t size);
+
+/**
+ * Unpack message Enter_Bootloader.
+ *
+ * @param[out] dst_p Object to unpack the message into.
+ * @param[in] src_p Message to unpack.
+ * @param[in] size Size of src_p.
+ *
+ * @return zero(0) or negative error code.
+ */
+int PDH_enter_bootloader_unpack(
+    struct PDH_enter_bootloader_t *dst_p,
+    const uint8_t *src_p,
+    size_t size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hal/src/main/native/athena/rev/PHFrames.cpp b/hal/src/main/native/athena/rev/PHFrames.cpp
new file mode 100644
index 0000000..e7f77e0
--- /dev/null
+++ b/hal/src/main/native/athena/rev/PHFrames.cpp
@@ -0,0 +1,1720 @@
+/**

+ * The MIT License (MIT)

+ *

+ * Copyright (c) 2018-2019 Erik Moqvist

+ *

+ * Permission is hereby granted, free of charge, to any person

+ * obtaining a copy of this software and associated documentation

+ * files (the "Software"), to deal in the Software without

+ * restriction, including without limitation the rights to use, copy,

+ * modify, merge, publish, distribute, sublicense, and/or sell copies

+ * of the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND

+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS

+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN

+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN

+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

+ * SOFTWARE.

+ */

+

+/**

+ * This file was generated by cantools version

+ */

+

+#include <string.h>

+

+#include "PHFrames.h"

+

+static inline uint8_t pack_left_shift_u8(

+    uint8_t value,

+    uint8_t shift,

+    uint8_t mask)

+{

+    return (uint8_t)((uint8_t)(value << shift) & mask);

+}

+

+static inline uint8_t pack_left_shift_u16(

+    uint16_t value,

+    uint8_t shift,

+    uint8_t mask)

+{

+    return (uint8_t)((uint8_t)(value << shift) & mask);

+}

+

+static inline uint8_t pack_right_shift_u16(

+    uint16_t value,

+    uint8_t shift,

+    uint8_t mask)

+{

+    return (uint8_t)((uint8_t)(value >> shift) & mask);

+}

+

+static inline uint16_t unpack_left_shift_u16(

+    uint8_t value,

+    uint8_t shift,

+    uint8_t mask)

+{

+    return (uint16_t)((uint16_t)(value & mask) << shift);

+}

+

+static inline uint8_t unpack_right_shift_u8(

+    uint8_t value,

+    uint8_t shift,

+    uint8_t mask)

+{

+    return (uint8_t)((uint8_t)(value & mask) >> shift);

+}

+

+static inline uint16_t unpack_right_shift_u16(

+    uint8_t value,

+    uint8_t shift,

+    uint8_t mask)

+{

+    return (uint16_t)((uint16_t)(value & mask) >> shift);

+}

+

+int PH_set_all_pack(

+    uint8_t *dst_p,

+    const struct PH_set_all_t *src_p,

+    size_t size)

+{

+    if (size < 4u) {

+        return (-EINVAL);

+    }

+

+    memset(&dst_p[0], 0, 4);

+

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_0, 0u, 0x03u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_1, 2u, 0x0cu);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_2, 4u, 0x30u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_3, 6u, 0xc0u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_4, 0u, 0x03u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_5, 2u, 0x0cu);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_6, 4u, 0x30u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_7, 6u, 0xc0u);

+    dst_p[2] |= pack_left_shift_u8(src_p->channel_8, 0u, 0x03u);

+    dst_p[2] |= pack_left_shift_u8(src_p->channel_9, 2u, 0x0cu);

+    dst_p[2] |= pack_left_shift_u8(src_p->channel_10, 4u, 0x30u);

+    dst_p[2] |= pack_left_shift_u8(src_p->channel_11, 6u, 0xc0u);

+    dst_p[3] |= pack_left_shift_u8(src_p->channel_12, 0u, 0x03u);

+    dst_p[3] |= pack_left_shift_u8(src_p->channel_13, 2u, 0x0cu);

+    dst_p[3] |= pack_left_shift_u8(src_p->channel_14, 4u, 0x30u);

+    dst_p[3] |= pack_left_shift_u8(src_p->channel_15, 6u, 0xc0u);

+

+    return (4);

+}

+

+int PH_set_all_unpack(

+    struct PH_set_all_t *dst_p,

+    const uint8_t *src_p,

+    size_t size)

+{

+    if (size < 4u) {

+        return (-EINVAL);

+    }

+

+    dst_p->channel_0 = unpack_right_shift_u8(src_p[0], 0u, 0x03u);

+    dst_p->channel_1 = unpack_right_shift_u8(src_p[0], 2u, 0x0cu);

+    dst_p->channel_2 = unpack_right_shift_u8(src_p[0], 4u, 0x30u);

+    dst_p->channel_3 = unpack_right_shift_u8(src_p[0], 6u, 0xc0u);

+    dst_p->channel_4 = unpack_right_shift_u8(src_p[1], 0u, 0x03u);

+    dst_p->channel_5 = unpack_right_shift_u8(src_p[1], 2u, 0x0cu);

+    dst_p->channel_6 = unpack_right_shift_u8(src_p[1], 4u, 0x30u);

+    dst_p->channel_7 = unpack_right_shift_u8(src_p[1], 6u, 0xc0u);

+    dst_p->channel_8 = unpack_right_shift_u8(src_p[2], 0u, 0x03u);

+    dst_p->channel_9 = unpack_right_shift_u8(src_p[2], 2u, 0x0cu);

+    dst_p->channel_10 = unpack_right_shift_u8(src_p[2], 4u, 0x30u);

+    dst_p->channel_11 = unpack_right_shift_u8(src_p[2], 6u, 0xc0u);

+    dst_p->channel_12 = unpack_right_shift_u8(src_p[3], 0u, 0x03u);

+    dst_p->channel_13 = unpack_right_shift_u8(src_p[3], 2u, 0x0cu);

+    dst_p->channel_14 = unpack_right_shift_u8(src_p[3], 4u, 0x30u);

+    dst_p->channel_15 = unpack_right_shift_u8(src_p[3], 6u, 0xc0u);

+

+    return (0);

+}

+

+uint8_t PH_set_all_channel_0_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_0_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_0_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_1_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_1_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_1_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_2_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_2_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_2_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_3_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_3_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_3_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_4_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_4_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_4_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_5_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_5_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_5_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_6_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_6_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_6_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_7_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_7_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_7_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_8_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_8_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_8_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_9_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_9_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_9_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_10_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_10_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_10_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_11_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_11_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_11_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_12_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_12_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_12_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_13_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_13_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_13_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_14_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_14_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_14_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+uint8_t PH_set_all_channel_15_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_set_all_channel_15_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_set_all_channel_15_is_in_range(uint8_t value)

+{

+    return (value <= 3u);

+}

+

+int PH_pulse_once_pack(

+    uint8_t *dst_p,

+    const struct PH_pulse_once_t *src_p,

+    size_t size)

+{

+    if (size < 4u) {

+        return (-EINVAL);

+    }

+

+    memset(&dst_p[0], 0, 4);

+

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_0, 0u, 0x01u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_1, 1u, 0x02u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_2, 2u, 0x04u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_3, 3u, 0x08u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_4, 4u, 0x10u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_5, 5u, 0x20u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_6, 6u, 0x40u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_7, 7u, 0x80u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_8, 0u, 0x01u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_9, 1u, 0x02u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_10, 2u, 0x04u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_11, 3u, 0x08u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_12, 4u, 0x10u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_13, 5u, 0x20u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_14, 6u, 0x40u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_15, 7u, 0x80u);

+    dst_p[2] |= pack_left_shift_u16(src_p->pulse_length_ms, 0u, 0xffu);

+    dst_p[3] |= pack_right_shift_u16(src_p->pulse_length_ms, 8u, 0xffu);

+

+    return (4);

+}

+

+int PH_pulse_once_unpack(

+    struct PH_pulse_once_t *dst_p,

+    const uint8_t *src_p,

+    size_t size)

+{

+    if (size < 4u) {

+        return (-EINVAL);

+    }

+

+    dst_p->channel_0 = unpack_right_shift_u8(src_p[0], 0u, 0x01u);

+    dst_p->channel_1 = unpack_right_shift_u8(src_p[0], 1u, 0x02u);

+    dst_p->channel_2 = unpack_right_shift_u8(src_p[0], 2u, 0x04u);

+    dst_p->channel_3 = unpack_right_shift_u8(src_p[0], 3u, 0x08u);

+    dst_p->channel_4 = unpack_right_shift_u8(src_p[0], 4u, 0x10u);

+    dst_p->channel_5 = unpack_right_shift_u8(src_p[0], 5u, 0x20u);

+    dst_p->channel_6 = unpack_right_shift_u8(src_p[0], 6u, 0x40u);

+    dst_p->channel_7 = unpack_right_shift_u8(src_p[0], 7u, 0x80u);

+    dst_p->channel_8 = unpack_right_shift_u8(src_p[1], 0u, 0x01u);

+    dst_p->channel_9 = unpack_right_shift_u8(src_p[1], 1u, 0x02u);

+    dst_p->channel_10 = unpack_right_shift_u8(src_p[1], 2u, 0x04u);

+    dst_p->channel_11 = unpack_right_shift_u8(src_p[1], 3u, 0x08u);

+    dst_p->channel_12 = unpack_right_shift_u8(src_p[1], 4u, 0x10u);

+    dst_p->channel_13 = unpack_right_shift_u8(src_p[1], 5u, 0x20u);

+    dst_p->channel_14 = unpack_right_shift_u8(src_p[1], 6u, 0x40u);

+    dst_p->channel_15 = unpack_right_shift_u8(src_p[1], 7u, 0x80u);

+    dst_p->pulse_length_ms = unpack_right_shift_u16(src_p[2], 0u, 0xffu);

+    dst_p->pulse_length_ms |= unpack_left_shift_u16(src_p[3], 8u, 0xffu);

+

+    return (0);

+}

+

+uint8_t PH_pulse_once_channel_0_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_0_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_0_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_1_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_1_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_1_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_2_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_2_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_2_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_3_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_3_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_3_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_4_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_4_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_4_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_5_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_5_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_5_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_6_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_6_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_6_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_7_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_7_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_7_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_8_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_8_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_8_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_9_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_9_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_9_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_10_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_10_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_10_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_11_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_11_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_11_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_12_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_12_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_12_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_13_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_13_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_13_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_14_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_14_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_14_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_pulse_once_channel_15_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_pulse_once_channel_15_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_channel_15_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint16_t PH_pulse_once_pulse_length_ms_encode(double value)

+{

+    return (uint16_t)(value);

+}

+

+double PH_pulse_once_pulse_length_ms_decode(uint16_t value)

+{

+    return ((double)value);

+}

+

+bool PH_pulse_once_pulse_length_ms_is_in_range(uint16_t value)

+{

+    (void)value;

+

+    return (true);

+}

+

+int PH_status0_pack(

+    uint8_t *dst_p,

+    const struct PH_status0_t *src_p,

+    size_t size)

+{

+    if (size < 8u) {

+        return (-EINVAL);

+    }

+

+    memset(&dst_p[0], 0, 8);

+

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_0, 0u, 0x01u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_1, 1u, 0x02u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_2, 2u, 0x04u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_3, 3u, 0x08u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_4, 4u, 0x10u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_5, 5u, 0x20u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_6, 6u, 0x40u);

+    dst_p[0] |= pack_left_shift_u8(src_p->channel_7, 7u, 0x80u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_8, 0u, 0x01u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_9, 1u, 0x02u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_10, 2u, 0x04u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_11, 3u, 0x08u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_12, 4u, 0x10u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_13, 5u, 0x20u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_14, 6u, 0x40u);

+    dst_p[1] |= pack_left_shift_u8(src_p->channel_15, 7u, 0x80u);

+    dst_p[2] |= pack_left_shift_u8(src_p->analog_0, 0u, 0xffu);

+    dst_p[3] |= pack_left_shift_u8(src_p->analog_1, 0u, 0xffu);

+    dst_p[4] |= pack_left_shift_u8(src_p->digital_sensor, 0u, 0x01u);

+    dst_p[4] |= pack_left_shift_u8(src_p->brownout, 1u, 0x02u);

+    dst_p[4] |= pack_left_shift_u8(src_p->compressor_oc, 2u, 0x04u);

+    dst_p[4] |= pack_left_shift_u8(src_p->compressor_open, 3u, 0x08u);

+    dst_p[4] |= pack_left_shift_u8(src_p->solenoid_oc, 4u, 0x10u);

+    dst_p[4] |= pack_left_shift_u8(src_p->can_warning, 5u, 0x20u);

+    dst_p[4] |= pack_left_shift_u8(src_p->hardware_fault, 6u, 0x40u);

+    dst_p[5] |= pack_left_shift_u8(src_p->channel_0_fault, 0u, 0x01u);

+    dst_p[5] |= pack_left_shift_u8(src_p->channel_1_fault, 1u, 0x02u);

+    dst_p[5] |= pack_left_shift_u8(src_p->channel_2_fault, 2u, 0x04u);

+    dst_p[5] |= pack_left_shift_u8(src_p->channel_3_fault, 3u, 0x08u);

+    dst_p[5] |= pack_left_shift_u8(src_p->channel_4_fault, 4u, 0x10u);

+    dst_p[5] |= pack_left_shift_u8(src_p->channel_5_fault, 5u, 0x20u);

+    dst_p[5] |= pack_left_shift_u8(src_p->channel_6_fault, 6u, 0x40u);

+    dst_p[5] |= pack_left_shift_u8(src_p->channel_7_fault, 7u, 0x80u);

+    dst_p[6] |= pack_left_shift_u8(src_p->channel_8_fault, 0u, 0x01u);

+    dst_p[6] |= pack_left_shift_u8(src_p->channel_9_fault, 1u, 0x02u);

+    dst_p[6] |= pack_left_shift_u8(src_p->channel_10_fault, 2u, 0x04u);

+    dst_p[6] |= pack_left_shift_u8(src_p->channel_11_fault, 3u, 0x08u);

+    dst_p[6] |= pack_left_shift_u8(src_p->channel_12_fault, 4u, 0x10u);

+    dst_p[6] |= pack_left_shift_u8(src_p->channel_13_fault, 5u, 0x20u);

+    dst_p[6] |= pack_left_shift_u8(src_p->channel_14_fault, 6u, 0x40u);

+    dst_p[6] |= pack_left_shift_u8(src_p->channel_15_fault, 7u, 0x80u);

+    dst_p[7] |= pack_left_shift_u8(src_p->compressor_on, 0u, 0x01u);

+    dst_p[7] |= pack_left_shift_u8(src_p->system_enabled, 1u, 0x02u);

+

+    return (8);

+}

+

+int PH_status0_unpack(

+    struct PH_status0_t *dst_p,

+    const uint8_t *src_p,

+    size_t size)

+{

+    if (size < 8u) {

+        return (-EINVAL);

+    }

+

+    dst_p->channel_0 = unpack_right_shift_u8(src_p[0], 0u, 0x01u);

+    dst_p->channel_1 = unpack_right_shift_u8(src_p[0], 1u, 0x02u);

+    dst_p->channel_2 = unpack_right_shift_u8(src_p[0], 2u, 0x04u);

+    dst_p->channel_3 = unpack_right_shift_u8(src_p[0], 3u, 0x08u);

+    dst_p->channel_4 = unpack_right_shift_u8(src_p[0], 4u, 0x10u);

+    dst_p->channel_5 = unpack_right_shift_u8(src_p[0], 5u, 0x20u);

+    dst_p->channel_6 = unpack_right_shift_u8(src_p[0], 6u, 0x40u);

+    dst_p->channel_7 = unpack_right_shift_u8(src_p[0], 7u, 0x80u);

+    dst_p->channel_8 = unpack_right_shift_u8(src_p[1], 0u, 0x01u);

+    dst_p->channel_9 = unpack_right_shift_u8(src_p[1], 1u, 0x02u);

+    dst_p->channel_10 = unpack_right_shift_u8(src_p[1], 2u, 0x04u);

+    dst_p->channel_11 = unpack_right_shift_u8(src_p[1], 3u, 0x08u);

+    dst_p->channel_12 = unpack_right_shift_u8(src_p[1], 4u, 0x10u);

+    dst_p->channel_13 = unpack_right_shift_u8(src_p[1], 5u, 0x20u);

+    dst_p->channel_14 = unpack_right_shift_u8(src_p[1], 6u, 0x40u);

+    dst_p->channel_15 = unpack_right_shift_u8(src_p[1], 7u, 0x80u);

+    dst_p->analog_0 = unpack_right_shift_u8(src_p[2], 0u, 0xffu);

+    dst_p->analog_1 = unpack_right_shift_u8(src_p[3], 0u, 0xffu);

+    dst_p->digital_sensor = unpack_right_shift_u8(src_p[4], 0u, 0x01u);

+    dst_p->brownout = unpack_right_shift_u8(src_p[4], 1u, 0x02u);

+    dst_p->compressor_oc = unpack_right_shift_u8(src_p[4], 2u, 0x04u);

+    dst_p->compressor_open = unpack_right_shift_u8(src_p[4], 3u, 0x08u);

+    dst_p->solenoid_oc = unpack_right_shift_u8(src_p[4], 4u, 0x10u);

+    dst_p->can_warning = unpack_right_shift_u8(src_p[4], 5u, 0x20u);

+    dst_p->hardware_fault = unpack_right_shift_u8(src_p[4], 6u, 0x40u);

+    dst_p->channel_0_fault = unpack_right_shift_u8(src_p[5], 0u, 0x01u);

+    dst_p->channel_1_fault = unpack_right_shift_u8(src_p[5], 1u, 0x02u);

+    dst_p->channel_2_fault = unpack_right_shift_u8(src_p[5], 2u, 0x04u);

+    dst_p->channel_3_fault = unpack_right_shift_u8(src_p[5], 3u, 0x08u);

+    dst_p->channel_4_fault = unpack_right_shift_u8(src_p[5], 4u, 0x10u);

+    dst_p->channel_5_fault = unpack_right_shift_u8(src_p[5], 5u, 0x20u);

+    dst_p->channel_6_fault = unpack_right_shift_u8(src_p[5], 6u, 0x40u);

+    dst_p->channel_7_fault = unpack_right_shift_u8(src_p[5], 7u, 0x80u);

+    dst_p->channel_8_fault = unpack_right_shift_u8(src_p[6], 0u, 0x01u);

+    dst_p->channel_9_fault = unpack_right_shift_u8(src_p[6], 1u, 0x02u);

+    dst_p->channel_10_fault = unpack_right_shift_u8(src_p[6], 2u, 0x04u);

+    dst_p->channel_11_fault = unpack_right_shift_u8(src_p[6], 3u, 0x08u);

+    dst_p->channel_12_fault = unpack_right_shift_u8(src_p[6], 4u, 0x10u);

+    dst_p->channel_13_fault = unpack_right_shift_u8(src_p[6], 5u, 0x20u);

+    dst_p->channel_14_fault = unpack_right_shift_u8(src_p[6], 6u, 0x40u);

+    dst_p->channel_15_fault = unpack_right_shift_u8(src_p[6], 7u, 0x80u);

+    dst_p->compressor_on = unpack_right_shift_u8(src_p[7], 0u, 0x01u);

+    dst_p->system_enabled = unpack_right_shift_u8(src_p[7], 1u, 0x02u);

+

+    return (0);

+}

+

+uint8_t PH_status0_channel_0_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_0_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_0_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_1_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_1_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_1_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_2_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_2_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_2_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_3_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_3_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_3_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_4_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_4_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_4_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_5_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_5_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_5_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_6_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_6_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_6_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_7_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_7_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_7_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_8_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_8_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_8_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_9_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_9_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_9_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_10_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_10_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_10_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_11_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_11_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_11_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_12_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_12_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_12_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_13_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_13_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_13_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_14_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_14_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_14_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_15_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_15_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_15_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_analog_0_encode(double value)

+{

+    return (uint8_t)(value / 0.01961);

+}

+

+double PH_status0_analog_0_decode(uint8_t value)

+{

+    return ((double)value * 0.01961);

+}

+

+bool PH_status0_analog_0_is_in_range(uint8_t value)

+{

+    (void)value;

+

+    return (true);

+}

+

+uint8_t PH_status0_analog_1_encode(double value)

+{

+    return (uint8_t)(value / 0.01961);

+}

+

+double PH_status0_analog_1_decode(uint8_t value)

+{

+    return ((double)value * 0.01961);

+}

+

+bool PH_status0_analog_1_is_in_range(uint8_t value)

+{

+    (void)value;

+

+    return (true);

+}

+

+uint8_t PH_status0_digital_sensor_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_digital_sensor_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_digital_sensor_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_brownout_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_brownout_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_brownout_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_compressor_oc_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_compressor_oc_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_compressor_oc_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_compressor_open_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_compressor_open_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_compressor_open_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_solenoid_oc_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_solenoid_oc_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_solenoid_oc_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_can_warning_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_can_warning_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_can_warning_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_hardware_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_hardware_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_hardware_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_0_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_0_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_0_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_1_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_1_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_1_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_2_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_2_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_2_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_3_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_3_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_3_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_4_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_4_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_4_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_5_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_5_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_5_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_6_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_6_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_6_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_7_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_7_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_7_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_8_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_8_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_8_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_9_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_9_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_9_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_10_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_10_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_10_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_11_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_11_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_11_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_12_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_12_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_12_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_13_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_13_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_13_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_14_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_14_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_14_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_channel_15_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_channel_15_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_channel_15_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_compressor_on_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_compressor_on_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_compressor_on_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status0_system_enabled_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status0_system_enabled_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status0_system_enabled_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+int PH_status1_pack(

+    uint8_t *dst_p,

+    const struct PH_status1_t *src_p,

+    size_t size)

+{

+    if (size < 8u) {

+        return (-EINVAL);

+    }

+

+    memset(&dst_p[0], 0, 8);

+

+    dst_p[0] |= pack_left_shift_u8(src_p->v_bus, 0u, 0xffu);

+    dst_p[1] |= pack_left_shift_u16(src_p->solenoid_voltage, 0u, 0xffu);

+    dst_p[2] |= pack_right_shift_u16(src_p->solenoid_voltage, 8u, 0x0fu);

+    dst_p[4] |= pack_left_shift_u8(src_p->compressor_current, 0u, 0xffu);

+    dst_p[5] |= pack_left_shift_u8(src_p->solenoid_current, 0u, 0xffu);

+    dst_p[6] |= pack_left_shift_u8(src_p->sticky_brownout, 0u, 0x01u);

+    dst_p[6] |= pack_left_shift_u8(src_p->sticky_compressor_over_current, 1u, 0x02u);

+    dst_p[6] |= pack_left_shift_u8(src_p->sticky_compressor_not_present, 2u, 0x04u);

+    dst_p[6] |= pack_left_shift_u8(src_p->sticky_solenoid_over_current, 3u, 0x08u);

+    dst_p[6] |= pack_left_shift_u8(src_p->sticky_can_warning, 4u, 0x10u);

+    dst_p[6] |= pack_left_shift_u8(src_p->sticky_can_bus_off, 5u, 0x20u);

+    dst_p[6] |= pack_left_shift_u8(src_p->sticky_hardware_fault, 6u, 0x40u);

+    dst_p[6] |= pack_left_shift_u8(src_p->sticky_firmware_fault, 7u, 0x80u);

+    dst_p[7] |= pack_left_shift_u8(src_p->sticky_has_reset, 0u, 0x01u);

+

+    return (8);

+}

+

+int PH_status1_unpack(

+    struct PH_status1_t *dst_p,

+    const uint8_t *src_p,

+    size_t size)

+{

+    if (size < 8u) {

+        return (-EINVAL);

+    }

+

+    dst_p->v_bus = unpack_right_shift_u8(src_p[0], 0u, 0xffu);

+    dst_p->solenoid_voltage = unpack_right_shift_u16(src_p[1], 0u, 0xffu);

+    dst_p->solenoid_voltage |= unpack_left_shift_u16(src_p[2], 8u, 0x0fu);

+    dst_p->compressor_current = unpack_right_shift_u8(src_p[4], 0u, 0xffu);

+    dst_p->solenoid_current = unpack_right_shift_u8(src_p[5], 0u, 0xffu);

+    dst_p->sticky_brownout = unpack_right_shift_u8(src_p[6], 0u, 0x01u);

+    dst_p->sticky_compressor_over_current = unpack_right_shift_u8(src_p[6], 1u, 0x02u);

+    dst_p->sticky_compressor_not_present = unpack_right_shift_u8(src_p[6], 2u, 0x04u);

+    dst_p->sticky_solenoid_over_current = unpack_right_shift_u8(src_p[6], 3u, 0x08u);

+    dst_p->sticky_can_warning = unpack_right_shift_u8(src_p[6], 4u, 0x10u);

+    dst_p->sticky_can_bus_off = unpack_right_shift_u8(src_p[6], 5u, 0x20u);

+    dst_p->sticky_hardware_fault = unpack_right_shift_u8(src_p[6], 6u, 0x40u);

+    dst_p->sticky_firmware_fault = unpack_right_shift_u8(src_p[6], 7u, 0x80u);

+    dst_p->sticky_has_reset = unpack_right_shift_u8(src_p[7], 0u, 0x01u);

+

+    return (0);

+}

+

+uint8_t PH_status1_v_bus_encode(double value)

+{

+    return (uint8_t)((value - 4.0) / 0.0625);

+}

+

+double PH_status1_v_bus_decode(uint8_t value)

+{

+    return (((double)value * 0.0625) + 4.0);

+}

+

+bool PH_status1_v_bus_is_in_range(uint8_t value)

+{

+    return (value <= 192u);

+}

+

+uint16_t PH_status1_solenoid_voltage_encode(double value)

+{

+    return (uint16_t)(value / 0.0078125);

+}

+

+double PH_status1_solenoid_voltage_decode(uint16_t value)

+{

+    return ((double)value * 0.0078125);

+}

+

+bool PH_status1_solenoid_voltage_is_in_range(uint16_t value)

+{

+    return (value <= 4096u);

+}

+

+uint8_t PH_status1_compressor_current_encode(double value)

+{

+    return (uint8_t)(value / 0.125);

+}

+

+double PH_status1_compressor_current_decode(uint8_t value)

+{

+    return ((double)value * 0.125);

+}

+

+bool PH_status1_compressor_current_is_in_range(uint8_t value)

+{

+    (void)value;

+

+    return (true);

+}

+

+uint8_t PH_status1_solenoid_current_encode(double value)

+{

+    return (uint8_t)(value / 0.125);

+}

+

+double PH_status1_solenoid_current_decode(uint8_t value)

+{

+    return ((double)value * 0.125);

+}

+

+bool PH_status1_solenoid_current_is_in_range(uint8_t value)

+{

+    (void)value;

+

+    return (true);

+}

+

+uint8_t PH_status1_sticky_brownout_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_brownout_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_brownout_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status1_sticky_compressor_over_current_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_compressor_over_current_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_compressor_over_current_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status1_sticky_compressor_not_present_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_compressor_not_present_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_compressor_not_present_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status1_sticky_solenoid_over_current_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_solenoid_over_current_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_solenoid_over_current_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status1_sticky_can_warning_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_can_warning_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_can_warning_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status1_sticky_can_bus_off_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_can_bus_off_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_can_bus_off_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status1_sticky_hardware_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_hardware_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_hardware_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status1_sticky_firmware_fault_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_firmware_fault_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_firmware_fault_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

+

+uint8_t PH_status1_sticky_has_reset_encode(double value)

+{

+    return (uint8_t)(value);

+}

+

+double PH_status1_sticky_has_reset_decode(uint8_t value)

+{

+    return ((double)value);

+}

+

+bool PH_status1_sticky_has_reset_is_in_range(uint8_t value)

+{

+    return (value <= 1u);

+}

diff --git a/hal/src/main/native/athena/rev/PHFrames.h b/hal/src/main/native/athena/rev/PHFrames.h
new file mode 100644
index 0000000..295be0a
--- /dev/null
+++ b/hal/src/main/native/athena/rev/PHFrames.h
@@ -0,0 +1,3249 @@
+/**

+ * The MIT License (MIT)

+ *

+ * Copyright (c) 2018-2019 Erik Moqvist

+ *

+ * Permission is hereby granted, free of charge, to any person

+ * obtaining a copy of this software and associated documentation

+ * files (the "Software"), to deal in the Software without

+ * restriction, including without limitation the rights to use, copy,

+ * modify, merge, publish, distribute, sublicense, and/or sell copies

+ * of the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND

+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS

+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN

+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN

+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

+ * SOFTWARE.

+ */

+

+/**

+ * This file was generated by cantools version

+ */

+

+#ifndef PH_H

+#define PH_H

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+#include <stdint.h>

+#include <stdbool.h>

+#include <stddef.h>

+

+#ifndef EINVAL

+#    define EINVAL 22

+#endif

+

+/* Frame ids. */

+#define PH_SET_ALL_FRAME_ID (0x9050c00u)

+#define PH_PULSE_ONCE_FRAME_ID (0x9050c40u)

+#define PH_STATUS0_FRAME_ID (0x9051800u)

+#define PH_STATUS1_FRAME_ID (0x9051840u)

+

+/* Frame lengths in bytes. */

+#define PH_SET_ALL_LENGTH (4u)

+#define PH_PULSE_ONCE_LENGTH (4u)

+#define PH_STATUS0_LENGTH (8u)

+#define PH_STATUS1_LENGTH (8u)

+

+/* Extended or standard frame types. */

+#define PH_SET_ALL_IS_EXTENDED (1)

+#define PH_PULSE_ONCE_IS_EXTENDED (1)

+#define PH_STATUS0_IS_EXTENDED (1)

+#define PH_STATUS1_IS_EXTENDED (1)

+

+/* Frame cycle times in milliseconds. */

+

+

+/* Signal choices. */

+

+

+/**

+ * Signals in message SetAll.

+ *

+ * Set state of all channels

+ *

+ * All signal values are as on the CAN bus.

+ */

+struct PH_set_all_t {

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_0 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_1 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_2 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_3 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_4 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_5 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_6 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_7 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_8 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_9 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_10 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_11 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_12 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_13 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_14 : 2;

+

+    /**

+     * Range: 0..3 (0..3 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_15 : 2;

+};

+

+/**

+ * Signals in message PulseOnce.

+ *

+ * Pulse selected channels once

+ *

+ * All signal values are as on the CAN bus.

+ */

+struct PH_pulse_once_t {

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_0 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_1 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_2 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_3 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_4 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_5 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_6 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_7 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_8 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_9 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_10 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_11 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_12 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_13 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_14 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_15 : 1;

+

+    /**

+     * Range: 0..65535 (0..65535 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint16_t pulse_length_ms : 16;

+};

+

+/**

+ * Signals in message Status0.

+ *

+ * Periodic status frame 0

+ *

+ * All signal values are as on the CAN bus.

+ */

+struct PH_status0_t {

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_0 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_1 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_2 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_3 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_4 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_5 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_6 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_7 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_8 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_9 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_10 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_11 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_12 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_13 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_14 : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_15 : 1;

+

+    /**

+     * Range: 0..255 (0..5.00055 V)

+     * Scale: 0.01961

+     * Offset: 0

+     */

+    uint8_t analog_0 : 8;

+

+    /**

+     * Range: 0..255 (0..5.00055 V)

+     * Scale: 0.01961

+     * Offset: 0

+     */

+    uint8_t analog_1 : 8;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t digital_sensor : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t brownout : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t compressor_oc : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t compressor_open : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t solenoid_oc : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t can_warning : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t hardware_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_0_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_1_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_2_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_3_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_4_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_5_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_6_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_7_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_8_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_9_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_10_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_11_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_12_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_13_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_14_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t channel_15_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t compressor_on : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t system_enabled : 1;

+};

+

+/**

+ * Signals in message Status1.

+ *

+ * Periodic status frame 1

+ *

+ * All signal values are as on the CAN bus.

+ */

+struct PH_status1_t {

+    /**

+     * Range: 0..192 (4..16 V)

+     * Scale: 0.0625

+     * Offset: 4

+     */

+    uint8_t v_bus : 8;

+

+    /**

+     * Range: 0..4096 (0..32 V)

+     * Scale: 0.0078125

+     * Offset: 0

+     */

+    uint16_t solenoid_voltage : 12;

+

+    /**

+     * Range: 0..256 (0..32 A)

+     * Scale: 0.125

+     * Offset: 0

+     */

+    uint8_t compressor_current : 8;

+

+    /**

+     * Range: 0..256 (0..32 A)

+     * Scale: 0.125

+     * Offset: 0

+     */

+    uint8_t solenoid_current : 8;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_brownout : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_compressor_over_current : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_compressor_not_present : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_solenoid_over_current : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_can_warning : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_can_bus_off : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_hardware_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_firmware_fault : 1;

+

+    /**

+     * Range: 0..1 (0..1 -)

+     * Scale: 1

+     * Offset: 0

+     */

+    uint8_t sticky_has_reset : 1;

+};

+

+/**

+ * Pack message SetAll.

+ *

+ * @param[out] dst_p Buffer to pack the message into.

+ * @param[in] src_p Data to pack.

+ * @param[in] size Size of dst_p.

+ *

+ * @return Size of packed data, or negative error code.

+ */

+int PH_set_all_pack(

+    uint8_t *dst_p,

+    const struct PH_set_all_t *src_p,

+    size_t size);

+

+/**

+ * Unpack message SetAll.

+ *

+ * @param[out] dst_p Object to unpack the message into.

+ * @param[in] src_p Message to unpack.

+ * @param[in] size Size of src_p.

+ *

+ * @return zero(0) or negative error code.

+ */

+int PH_set_all_unpack(

+    struct PH_set_all_t *dst_p,

+    const uint8_t *src_p,

+    size_t size);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_0_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_0_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_0_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_1_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_1_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_1_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_2_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_2_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_2_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_3_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_3_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_3_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_4_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_4_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_4_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_5_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_5_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_5_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_6_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_6_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_6_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_7_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_7_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_7_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_8_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_8_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_8_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_9_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_9_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_9_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_10_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_10_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_10_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_11_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_11_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_11_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_12_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_12_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_12_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_13_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_13_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_13_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_14_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_14_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_14_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_set_all_channel_15_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_set_all_channel_15_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_set_all_channel_15_is_in_range(uint8_t value);

+

+/**

+ * Pack message PulseOnce.

+ *

+ * @param[out] dst_p Buffer to pack the message into.

+ * @param[in] src_p Data to pack.

+ * @param[in] size Size of dst_p.

+ *

+ * @return Size of packed data, or negative error code.

+ */

+int PH_pulse_once_pack(

+    uint8_t *dst_p,

+    const struct PH_pulse_once_t *src_p,

+    size_t size);

+

+/**

+ * Unpack message PulseOnce.

+ *

+ * @param[out] dst_p Object to unpack the message into.

+ * @param[in] src_p Message to unpack.

+ * @param[in] size Size of src_p.

+ *

+ * @return zero(0) or negative error code.

+ */

+int PH_pulse_once_unpack(

+    struct PH_pulse_once_t *dst_p,

+    const uint8_t *src_p,

+    size_t size);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_0_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_0_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_0_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_1_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_1_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_1_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_2_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_2_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_2_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_3_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_3_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_3_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_4_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_4_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_4_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_5_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_5_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_5_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_6_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_6_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_6_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_7_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_7_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_7_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_8_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_8_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_8_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_9_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_9_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_9_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_10_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_10_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_10_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_11_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_11_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_11_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_12_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_12_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_12_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_13_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_13_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_13_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_14_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_14_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_14_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_pulse_once_channel_15_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_channel_15_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_channel_15_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint16_t PH_pulse_once_pulse_length_ms_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_pulse_once_pulse_length_ms_decode(uint16_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_pulse_once_pulse_length_ms_is_in_range(uint16_t value);

+

+/**

+ * Pack message Status0.

+ *

+ * @param[out] dst_p Buffer to pack the message into.

+ * @param[in] src_p Data to pack.

+ * @param[in] size Size of dst_p.

+ *

+ * @return Size of packed data, or negative error code.

+ */

+int PH_status0_pack(

+    uint8_t *dst_p,

+    const struct PH_status0_t *src_p,

+    size_t size);

+

+/**

+ * Unpack message Status0.

+ *

+ * @param[out] dst_p Object to unpack the message into.

+ * @param[in] src_p Message to unpack.

+ * @param[in] size Size of src_p.

+ *

+ * @return zero(0) or negative error code.

+ */

+int PH_status0_unpack(

+    struct PH_status0_t *dst_p,

+    const uint8_t *src_p,

+    size_t size);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_0_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_0_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_0_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_1_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_1_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_1_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_2_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_2_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_2_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_3_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_3_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_3_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_4_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_4_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_4_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_5_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_5_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_5_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_6_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_6_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_6_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_7_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_7_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_7_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_8_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_8_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_8_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_9_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_9_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_9_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_10_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_10_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_10_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_11_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_11_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_11_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_12_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_12_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_12_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_13_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_13_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_13_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_14_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_14_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_14_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_15_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_15_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_15_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_analog_0_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_analog_0_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_analog_0_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_analog_1_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_analog_1_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_analog_1_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_digital_sensor_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_digital_sensor_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_digital_sensor_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_brownout_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_brownout_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_brownout_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_compressor_oc_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_compressor_oc_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_compressor_oc_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_compressor_open_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_compressor_open_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_compressor_open_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_solenoid_oc_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_solenoid_oc_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_solenoid_oc_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_can_warning_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_can_warning_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_can_warning_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_hardware_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_hardware_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_hardware_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_0_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_0_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_0_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_1_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_1_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_1_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_2_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_2_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_2_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_3_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_3_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_3_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_4_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_4_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_4_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_5_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_5_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_5_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_6_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_6_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_6_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_7_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_7_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_7_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_8_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_8_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_8_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_9_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_9_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_9_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_10_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_10_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_10_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_11_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_11_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_11_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_12_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_12_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_12_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_13_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_13_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_13_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_14_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_14_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_14_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_channel_15_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_channel_15_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_channel_15_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_compressor_on_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_compressor_on_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_compressor_on_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status0_system_enabled_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status0_system_enabled_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status0_system_enabled_is_in_range(uint8_t value);

+

+/**

+ * Pack message Status1.

+ *

+ * @param[out] dst_p Buffer to pack the message into.

+ * @param[in] src_p Data to pack.

+ * @param[in] size Size of dst_p.

+ *

+ * @return Size of packed data, or negative error code.

+ */

+int PH_status1_pack(

+    uint8_t *dst_p,

+    const struct PH_status1_t *src_p,

+    size_t size);

+

+/**

+ * Unpack message Status1.

+ *

+ * @param[out] dst_p Object to unpack the message into.

+ * @param[in] src_p Message to unpack.

+ * @param[in] size Size of src_p.

+ *

+ * @return zero(0) or negative error code.

+ */

+int PH_status1_unpack(

+    struct PH_status1_t *dst_p,

+    const uint8_t *src_p,

+    size_t size);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_v_bus_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_v_bus_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_v_bus_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint16_t PH_status1_solenoid_voltage_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_solenoid_voltage_decode(uint16_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_solenoid_voltage_is_in_range(uint16_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_compressor_current_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_compressor_current_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_compressor_current_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_solenoid_current_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_solenoid_current_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_solenoid_current_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_brownout_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_brownout_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_brownout_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_compressor_over_current_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_compressor_over_current_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_compressor_over_current_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_compressor_not_present_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_compressor_not_present_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_compressor_not_present_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_solenoid_over_current_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_solenoid_over_current_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_solenoid_over_current_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_can_warning_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_can_warning_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_can_warning_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_can_bus_off_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_can_bus_off_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_can_bus_off_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_hardware_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_hardware_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_hardware_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_firmware_fault_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_firmware_fault_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_firmware_fault_is_in_range(uint8_t value);

+

+/**

+ * Encode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to encode.

+ *

+ * @return Encoded signal.

+ */

+uint8_t PH_status1_sticky_has_reset_encode(double value);

+

+/**

+ * Decode given signal by applying scaling and offset.

+ *

+ * @param[in] value Signal to decode.

+ *

+ * @return Decoded signal.

+ */

+double PH_status1_sticky_has_reset_decode(uint8_t value);

+

+/**

+ * Check that given signal is in allowed range.

+ *

+ * @param[in] value Signal to check.

+ *

+ * @return true if in range, false otherwise.

+ */

+bool PH_status1_sticky_has_reset_is_in_range(uint8_t value);

+

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif

diff --git a/hal/src/main/native/cpp/ErrorHandling.cpp b/hal/src/main/native/cpp/ErrorHandling.cpp
new file mode 100644
index 0000000..ad1b40b
--- /dev/null
+++ b/hal/src/main/native/cpp/ErrorHandling.cpp
@@ -0,0 +1,60 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <fmt/format.h>
+#include <wpi/SmallString.h>
+
+#include "hal/Errors.h"
+#include "hal/HALBase.h"
+
+namespace {
+struct LastErrorStorage {
+  int32_t status;
+  wpi::SmallString<512> message;
+};
+}  // namespace
+
+static LastErrorStorage& GetThreadLastError() {
+  thread_local LastErrorStorage lastError;
+  return lastError;
+}
+
+namespace hal {
+void SetLastError(int32_t* status, std::string_view value) {
+  LastErrorStorage& lastError = GetThreadLastError();
+  lastError.message = value;
+  lastError.status = *status;
+  *status = HAL_USE_LAST_ERROR;
+}
+
+void SetLastErrorIndexOutOfRange(int32_t* status, std::string_view message,
+                                 int32_t minimum, int32_t maximum,
+                                 int32_t requested) {
+  SetLastError(
+      status,
+      fmt::format("{}\n Status: {}\n  Minimum: {} Maximum: {} Requested: {}",
+                  message, *status, minimum, maximum, requested));
+}
+
+void SetLastErrorPreviouslyAllocated(int32_t* status, std::string_view message,
+                                     int32_t channel,
+                                     std::string_view previousAllocation) {
+  hal::SetLastError(status,
+                    fmt::format("{} {} previously allocated.\n"
+                                "Location of the previous allocation:\n{}\n"
+                                "Location of the current allocation:",
+                                message, channel, previousAllocation));
+}
+}  // namespace hal
+
+extern "C" {
+const char* HAL_GetLastError(int32_t* status) {
+  if (*status == HAL_USE_LAST_ERROR) {
+    LastErrorStorage& lastError = GetThreadLastError();
+    *status = lastError.status;
+    return lastError.message.c_str();
+  }
+  return HAL_GetErrorMessage(*status);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/Main.cpp b/hal/src/main/native/cpp/Main.cpp
index a37c2b0..a43a108 100644
--- a/hal/src/main/native/cpp/Main.cpp
+++ b/hal/src/main/native/cpp/Main.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/Main.h"
 
@@ -36,14 +33,12 @@
   mainObj->gExitCv.notify_all();
 }
 
-namespace hal {
-namespace init {
+namespace hal::init {
 void InitializeMain() {
   static MainObj mO;
   mainObj = &mO;
 }
-}  // namespace init
-}  // namespace hal
+}  // namespace hal::init
 
 extern "C" {
 
@@ -55,10 +50,16 @@
   gExitFunc = exitFunc;
 }
 
-HAL_Bool HAL_HasMain(void) { return gHasMain; }
+HAL_Bool HAL_HasMain(void) {
+  return gHasMain;
+}
 
-void HAL_RunMain(void) { gMainFunc(gMainParam); }
+void HAL_RunMain(void) {
+  gMainFunc(gMainParam);
+}
 
-void HAL_ExitMain(void) { gExitFunc(gMainParam); }
+void HAL_ExitMain(void) {
+  gExitFunc(gMainParam);
+}
 
 }  // extern "C"
diff --git a/hal/src/main/native/cpp/cpp/fpga_clock.cpp b/hal/src/main/native/cpp/cpp/fpga_clock.cpp
index ae65ee7..550596a 100644
--- a/hal/src/main/native/cpp/cpp/fpga_clock.cpp
+++ b/hal/src/main/native/cpp/cpp/fpga_clock.cpp
@@ -1,15 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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/cpp/fpga_clock.h"
 
+#include <cstdio>
 #include <limits>
 
-#include <wpi/raw_ostream.h>
+#include <fmt/format.h>
 
 #include "hal/HALBase.h"
 
@@ -22,11 +20,12 @@
   int32_t status = 0;
   uint64_t currentTime = HAL_GetFPGATime(&status);
   if (status != 0) {
-    wpi::errs()
-        << "Call to HAL_GetFPGATime failed in fpga_clock::now() with status "
-        << status
-        << ". Initialization might have failed. Time will not be correct\n";
-    wpi::errs().flush();
+    fmt::print(
+        stderr,
+        "Call to HAL_GetFPGATime failed in fpga_clock::now() with status {}. "
+        "Initialization might have failed. Time will not be correct\n",
+        status);
+    std::fflush(stderr);
     return epoch();
   }
   return time_point(std::chrono::microseconds(currentTime));
diff --git a/hal/src/main/native/cpp/handles/HandlesInternal.cpp b/hal/src/main/native/cpp/handles/HandlesInternal.cpp
index 5e66ce1..80dca71 100644
--- a/hal/src/main/native/cpp/handles/HandlesInternal.cpp
+++ b/hal/src/main/native/cpp/handles/HandlesInternal.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/handles/HandlesInternal.h"
 
@@ -80,9 +77,13 @@
 }
 HAL_Handle createHandle(int16_t index, HAL_HandleEnum handleType,
                         int16_t version) {
-  if (index < 0) return HAL_kInvalidHandle;
+  if (index < 0) {
+    return HAL_kInvalidHandle;
+  }
   uint8_t hType = static_cast<uint8_t>(handleType);
-  if (hType == 0 || hType > 127) return HAL_kInvalidHandle;
+  if (hType == 0 || hType > 127) {
+    return HAL_kInvalidHandle;
+  }
   // set last 8 bits, then shift to first 8 bits
   HAL_Handle handle = hType;
   handle = handle << 8;
diff --git a/hal/src/main/native/cpp/jni/AccelerometerJNI.cpp b/hal/src/main/native/cpp/jni/AccelerometerJNI.cpp
index 6d0d256..d2c107e 100644
--- a/hal/src/main/native/cpp/jni/AccelerometerJNI.cpp
+++ b/hal/src/main/native/cpp/jni/AccelerometerJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp b/hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp
index 3d74b24..75da176 100644
--- a/hal/src/main/native/cpp/jni/AddressableLEDJNI.cpp
+++ b/hal/src/main/native/cpp/jni/AddressableLEDJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp b/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp
index c06e513..154301f 100644
--- a/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp
+++ b/hal/src/main/native/cpp/jni/AnalogGyroJNI.cpp
@@ -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.
 
 #include <jni.h>
 
 #include <cassert>
 
+#include <wpi/jni_util.h>
+
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_AnalogGyroJNI.h"
 #include "hal/AnalogGyro.h"
@@ -27,8 +26,9 @@
   (JNIEnv* env, jclass, jint id)
 {
   int32_t status = 0;
-  HAL_GyroHandle handle =
-      HAL_InitializeAnalogGyro((HAL_AnalogInputHandle)id, &status);
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
+  HAL_GyroHandle handle = HAL_InitializeAnalogGyro((HAL_AnalogInputHandle)id,
+                                                   stack.c_str(), &status);
   // Analog input does range checking, so we don't need to do so.
   CheckStatusForceThrow(env, status);
   return (jint)handle;
diff --git a/hal/src/main/native/cpp/jni/AnalogJNI.cpp b/hal/src/main/native/cpp/jni/AnalogJNI.cpp
index 8b920ac..a2cccb6 100644
--- a/hal/src/main/native/cpp/jni/AnalogJNI.cpp
+++ b/hal/src/main/native/cpp/jni/AnalogJNI.cpp
@@ -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.
 
 #include <jni.h>
 
 #include <cassert>
 
+#include <wpi/jni_util.h>
+
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_AnalogJNI.h"
 #include "hal/AnalogAccumulator.h"
@@ -32,9 +31,10 @@
   (JNIEnv* env, jclass, jint id)
 {
   int32_t status = 0;
-  auto analog = HAL_InitializeAnalogInputPort((HAL_PortHandle)id, &status);
-  CheckStatusRange(env, status, 0, HAL_GetNumAnalogInputs(),
-                   hal::getPortHandleChannel((HAL_PortHandle)id));
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
+  auto analog =
+      HAL_InitializeAnalogInputPort((HAL_PortHandle)id, stack.c_str(), &status);
+  CheckStatusForceThrow(env, status);
   return (jint)analog;
 }
 
@@ -60,10 +60,10 @@
   (JNIEnv* env, jclass, jint id)
 {
   int32_t status = 0;
-  HAL_AnalogOutputHandle analog =
-      HAL_InitializeAnalogOutputPort((HAL_PortHandle)id, &status);
-  CheckStatusRange(env, status, 0, HAL_GetNumAnalogOutputs(),
-                   hal::getPortHandleChannel((HAL_PortHandle)id));
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
+  HAL_AnalogOutputHandle analog = HAL_InitializeAnalogOutputPort(
+      (HAL_PortHandle)id, stack.c_str(), &status);
+  CheckStatusForceThrow(env, status);
   return (jlong)analog;
 }
 
@@ -298,6 +298,22 @@
 
 /*
  * Class:     edu_wpi_first_hal_AnalogJNI
+ * Method:    getAnalogValueToVolts
+ * Signature: (II)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_AnalogJNI_getAnalogValueToVolts
+  (JNIEnv* env, jclass, jint id, jint rawValue)
+{
+  int32_t status = 0;
+  jdouble returnValue =
+      HAL_GetAnalogValueToVolts((HAL_AnalogInputHandle)id, rawValue, &status);
+  CheckStatus(env, status);
+  return returnValue;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_AnalogJNI
  * Method:    getAnalogVoltage
  * Signature: (I)D
  */
diff --git a/hal/src/main/native/cpp/jni/CANAPIJNI.cpp b/hal/src/main/native/cpp/jni/CANAPIJNI.cpp
index f42cc2f..106167a 100644
--- a/hal/src/main/native/cpp/jni/CANAPIJNI.cpp
+++ b/hal/src/main/native/cpp/jni/CANAPIJNI.cpp
@@ -1,17 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include <jni.h>
 
 #include <cassert>
 
-#include <wpi/SmallString.h>
 #include <wpi/jni_util.h>
-#include <wpi/raw_ostream.h>
 
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_CANAPIJNI.h"
@@ -197,11 +192,15 @@
   if (!CheckStatus(env, status)) {
     return false;
   }
-  if (dataLength > 8) dataLength = 8;
+  if (dataLength > 8) {
+    dataLength = 8;
+  }
 
   jbyteArray toSetArray = SetCANDataObject(env, data, dataLength, timestamp);
   auto javaLen = env->GetArrayLength(toSetArray);
-  if (javaLen < dataLength) dataLength = javaLen;
+  if (javaLen < dataLength) {
+    dataLength = javaLen;
+  }
   env->SetByteArrayRegion(toSetArray, 0, dataLength,
                           reinterpret_cast<jbyte*>(dataTemp));
   return true;
@@ -229,11 +228,15 @@
   if (!CheckStatus(env, status)) {
     return false;
   }
-  if (dataLength > 8) dataLength = 8;
+  if (dataLength > 8) {
+    dataLength = 8;
+  }
 
   jbyteArray toSetArray = SetCANDataObject(env, data, dataLength, timestamp);
   auto javaLen = env->GetArrayLength(toSetArray);
-  if (javaLen < dataLength) dataLength = javaLen;
+  if (javaLen < dataLength) {
+    dataLength = javaLen;
+  }
   env->SetByteArrayRegion(toSetArray, 0, dataLength,
                           reinterpret_cast<jbyte*>(dataTemp));
   return true;
@@ -262,11 +265,15 @@
   if (!CheckStatus(env, status)) {
     return false;
   }
-  if (dataLength > 8) dataLength = 8;
+  if (dataLength > 8) {
+    dataLength = 8;
+  }
 
   jbyteArray toSetArray = SetCANDataObject(env, data, dataLength, timestamp);
   auto javaLen = env->GetArrayLength(toSetArray);
-  if (javaLen < dataLength) dataLength = javaLen;
+  if (javaLen < dataLength) {
+    dataLength = javaLen;
+  }
   env->SetByteArrayRegion(toSetArray, 0, dataLength,
                           reinterpret_cast<jbyte*>(dataTemp));
   return true;
diff --git a/hal/src/main/native/cpp/jni/CANJNI.cpp b/hal/src/main/native/cpp/jni/CANJNI.cpp
index 42b484b..968f656 100644
--- a/hal/src/main/native/cpp/jni/CANJNI.cpp
+++ b/hal/src/main/native/cpp/jni/CANJNI.cpp
@@ -1,17 +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 <jni.h>
 
 #include <cassert>
 
-#include <wpi/SmallString.h>
 #include <wpi/jni_util.h>
-#include <wpi/raw_ostream.h>
 
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_can_CANJNI.h"
@@ -64,19 +59,21 @@
   HAL_CAN_ReceiveMessage(messageIDPtr, messageIDMask, buffer, &dataSize,
                          timeStampPtr, &status);
 
-  if (!CheckCANStatus(env, status, *messageIDPtr)) return nullptr;
+  if (!CheckCANStatus(env, status, *messageIDPtr)) {
+    return nullptr;
+  }
   return MakeJByteArray(env,
-                        wpi::StringRef{reinterpret_cast<const char*>(buffer),
-                                       static_cast<size_t>(dataSize)});
+                        std::string_view{reinterpret_cast<const char*>(buffer),
+                                         static_cast<size_t>(dataSize)});
 }
 
 /*
  * Class:     edu_wpi_first_hal_can_CANJNI
- * Method:    GetCANStatus
+ * Method:    getCANStatus
  * Signature: (Ljava/lang/Object;)V
  */
 JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_can_CANJNI_GetCANStatus
+Java_edu_wpi_first_hal_can_CANJNI_getCANStatus
   (JNIEnv* env, jclass, jobject canStatus)
 {
   float percentBusUtilization = 0;
@@ -88,7 +85,9 @@
   HAL_CAN_GetCANStatus(&percentBusUtilization, &busOffCount, &txFullCount,
                        &receiveErrorCount, &transmitErrorCount, &status);
 
-  if (!CheckStatus(env, status)) return;
+  if (!CheckStatus(env, status)) {
+    return;
+  }
 
   SetCanStatusObject(env, canStatus, percentBusUtilization, busOffCount,
                      txFullCount, receiveErrorCount, transmitErrorCount);
diff --git a/hal/src/main/native/cpp/jni/CTREPCMJNI.cpp b/hal/src/main/native/cpp/jni/CTREPCMJNI.cpp
new file mode 100644
index 0000000..4d22f66
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/CTREPCMJNI.cpp
@@ -0,0 +1,340 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_CTREPCMJNI.h"
+#include "hal/CTREPCM.h"
+#include "hal/Ports.h"
+#include "hal/handles/HandlesInternal.h"
+
+using namespace hal;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    initialize
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_initialize
+  (JNIEnv* env, jclass, jint module)
+{
+  int32_t status = 0;
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
+  auto handle = HAL_InitializeCTREPCM(module, stack.c_str(), &status);
+  CheckStatusForceThrow(env, status);
+  return handle;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    free
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_free
+  (JNIEnv* env, jclass, jint handle)
+{
+  HAL_FreeCTREPCM(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    checkSolenoidChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_checkSolenoidChannel
+  (JNIEnv*, jclass, jint channel)
+{
+  return HAL_CheckCTREPCMSolenoidChannel(channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getCompressor
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getCompressor
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMCompressor(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    setClosedLoopControl
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_setClosedLoopControl
+  (JNIEnv* env, jclass, jint handle, jboolean enabled)
+{
+  int32_t status = 0;
+  HAL_SetCTREPCMClosedLoopControl(handle, enabled, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getClosedLoopControl
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getClosedLoopControl
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMClosedLoopControl(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getPressureSwitch
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getPressureSwitch
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMPressureSwitch(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getCompressorCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getCompressorCurrent
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMCompressorCurrent(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getCompressorCurrentTooHighFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getCompressorCurrentTooHighFault
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMCompressorCurrentTooHighFault(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getCompressorCurrentTooHighStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getCompressorCurrentTooHighStickyFault
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result =
+      HAL_GetCTREPCMCompressorCurrentTooHighStickyFault(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getCompressorShortedFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getCompressorShortedFault
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMCompressorShortedFault(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getCompressorShortedStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getCompressorShortedStickyFault
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMCompressorShortedStickyFault(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getCompressorNotConnectedFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getCompressorNotConnectedFault
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMCompressorNotConnectedFault(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getCompressorNotConnectedStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getCompressorNotConnectedStickyFault
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result =
+      HAL_GetCTREPCMCompressorNotConnectedStickyFault(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getSolenoids
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getSolenoids
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMSolenoids(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    setSolenoids
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_setSolenoids
+  (JNIEnv* env, jclass, jint handle, jint mask, jint value)
+{
+  int32_t status = 0;
+  HAL_SetCTREPCMSolenoids(handle, mask, value, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getSolenoidDisabledList
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getSolenoidDisabledList
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMSolenoidDisabledList(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getSolenoidVoltageFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getSolenoidVoltageFault
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMSolenoidVoltageFault(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    getSolenoidVoltageStickyFault
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_getSolenoidVoltageStickyFault
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetCTREPCMSolenoidVoltageStickyFault(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    clearAllStickyFaults
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_clearAllStickyFaults
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  HAL_ClearAllCTREPCMStickyFaults(handle, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    fireOneShot
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_fireOneShot
+  (JNIEnv* env, jclass, jint handle, jint index)
+{
+  int32_t status = 0;
+  HAL_FireCTREPCMOneShot(handle, index, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_CTREPCMJNI
+ * Method:    setOneShotDuration
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_CTREPCMJNI_setOneShotDuration
+  (JNIEnv* env, jclass, jint handle, jint index, jint durMs)
+{
+  int32_t status = 0;
+  HAL_SetCTREPCMOneShotDuration(handle, index, durMs, &status);
+  CheckStatus(env, status, false);
+}
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/CompressorJNI.cpp b/hal/src/main/native/cpp/jni/CompressorJNI.cpp
deleted file mode 100644
index c214c60..0000000
--- a/hal/src/main/native/cpp/jni/CompressorJNI.cpp
+++ /dev/null
@@ -1,233 +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 "HALUtil.h"
-#include "edu_wpi_first_hal_CompressorJNI.h"
-#include "hal/Compressor.h"
-#include "hal/Ports.h"
-#include "hal/Solenoid.h"
-
-using namespace hal;
-
-extern "C" {
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    initializeCompressor
- * Signature: (B)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_initializeCompressor
-  (JNIEnv* env, jclass, jbyte module)
-{
-  int32_t status = 0;
-  auto handle = HAL_InitializeCompressor(module, &status);
-  CheckStatusRange(env, status, 0, HAL_GetNumPCMModules(), module);
-
-  return (jint)handle;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    checkCompressorModule
- * Signature: (B)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_checkCompressorModule
-  (JNIEnv* env, jclass, jbyte module)
-{
-  return HAL_CheckCompressorModule(module);
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressor
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressor
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressor((HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    setCompressorClosedLoopControl
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_setCompressorClosedLoopControl
-  (JNIEnv* env, jclass, jint compressorHandle, jboolean value)
-{
-  int32_t status = 0;
-  HAL_SetCompressorClosedLoopControl((HAL_CompressorHandle)compressorHandle,
-                                     value, &status);
-  CheckStatus(env, status);
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorClosedLoopControl
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorClosedLoopControl
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressorClosedLoopControl(
-      (HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorPressureSwitch
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorPressureSwitch
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressorPressureSwitch(
-      (HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorCurrent
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorCurrent
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  double val =
-      HAL_GetCompressorCurrent((HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorCurrentTooHighFault
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorCurrentTooHighFault
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressorCurrentTooHighFault(
-      (HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorCurrentTooHighStickyFault
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorCurrentTooHighStickyFault
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressorCurrentTooHighStickyFault(
-      (HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorShortedStickyFault
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorShortedStickyFault
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressorShortedStickyFault(
-      (HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorShortedFault
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorShortedFault
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressorShortedFault(
-      (HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorNotConnectedStickyFault
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorNotConnectedStickyFault
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressorNotConnectedStickyFault(
-      (HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    getCompressorNotConnectedFault
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_getCompressorNotConnectedFault
-  (JNIEnv* env, jclass, jint compressorHandle)
-{
-  int32_t status = 0;
-  bool val = HAL_GetCompressorNotConnectedFault(
-      (HAL_CompressorHandle)compressorHandle, &status);
-  CheckStatus(env, status);
-  return val;
-}
-/*
- * Class:     edu_wpi_first_hal_CompressorJNI
- * Method:    clearAllPCMStickyFaults
- * Signature: (B)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_CompressorJNI_clearAllPCMStickyFaults
-  (JNIEnv* env, jclass, jbyte module)
-{
-  int32_t status = 0;
-  HAL_ClearAllPCMStickyFaults(static_cast<int32_t>(module), &status);
-  CheckStatus(env, status);
-}
-
-}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/ConstantsJNI.cpp b/hal/src/main/native/cpp/jni/ConstantsJNI.cpp
index 9c4aa63..600b7f7 100644
--- a/hal/src/main/native/cpp/jni/ConstantsJNI.cpp
+++ b/hal/src/main/native/cpp/jni/ConstantsJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/CounterJNI.cpp b/hal/src/main/native/cpp/jni/CounterJNI.cpp
index 06cbceb..0565d5b 100644
--- a/hal/src/main/native/cpp/jni/CounterJNI.cpp
+++ b/hal/src/main/native/cpp/jni/CounterJNI.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 <jni.h>
 
@@ -122,12 +119,6 @@
   HAL_SetCounterDownSource((HAL_CounterHandle)id,
                            (HAL_Handle)digitalSourceHandle,
                            (HAL_AnalogTriggerType)analogTriggerType, &status);
-  if (status == PARAMETER_OUT_OF_RANGE) {
-    ThrowIllegalArgumentException(env,
-                                  "Counter only supports DownSource in "
-                                  "TwoPulse and ExternalDirection modes.");
-    return;
-  }
   CheckStatus(env, status);
 }
 
@@ -243,10 +234,6 @@
 {
   int32_t status = 0;
   HAL_SetCounterSamplesToAverage((HAL_CounterHandle)id, value, &status);
-  if (status == PARAMETER_OUT_OF_RANGE) {
-    ThrowBoundaryException(env, value, 1, 127);
-    return;
-  }
   CheckStatus(env, status);
 }
 
diff --git a/hal/src/main/native/cpp/jni/DIOJNI.cpp b/hal/src/main/native/cpp/jni/DIOJNI.cpp
index 428dd99..5cd6c2e 100644
--- a/hal/src/main/native/cpp/jni/DIOJNI.cpp
+++ b/hal/src/main/native/cpp/jni/DIOJNI.cpp
@@ -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.
 
 #include <jni.h>
 
 #include <cassert>
 
+#include <wpi/jni_util.h>
+
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_DIOJNI.h"
 #include "hal/DIO.h"
@@ -30,10 +29,10 @@
   (JNIEnv* env, jclass, jint id, jboolean input)
 {
   int32_t status = 0;
-  auto dio = HAL_InitializeDIOPort((HAL_PortHandle)id,
-                                   static_cast<uint8_t>(input), &status);
-  CheckStatusRange(env, status, 0, HAL_GetNumDigitalChannels(),
-                   hal::getPortHandleChannel((HAL_PortHandle)id));
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
+  auto dio = HAL_InitializeDIOPort(
+      (HAL_PortHandle)id, static_cast<uint8_t>(input), stack.c_str(), &status);
+  CheckStatusForceThrow(env, status);
   return (jint)dio;
 }
 
@@ -76,11 +75,11 @@
 /*
  * Class:     edu_wpi_first_hal_DIOJNI
  * Method:    setDIO
- * Signature: (IS)V
+ * Signature: (IZ)V
  */
 JNIEXPORT void JNICALL
 Java_edu_wpi_first_hal_DIOJNI_setDIO
-  (JNIEnv* env, jclass, jint id, jshort value)
+  (JNIEnv* env, jclass, jint id, jboolean value)
 {
   int32_t status = 0;
   HAL_SetDIO((HAL_DigitalHandle)id, value, &status);
diff --git a/hal/src/main/native/cpp/jni/DMAJNI.cpp b/hal/src/main/native/cpp/jni/DMAJNI.cpp
new file mode 100644
index 0000000..3e95c7b
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/DMAJNI.cpp
@@ -0,0 +1,416 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_DMAJNI.h"
+#include "hal/DMA.h"
+#include "hal/handles/HandlesInternal.h"
+
+using namespace hal;
+
+namespace hal {
+bool GetEncoderBaseHandle(HAL_EncoderHandle handle,
+                          HAL_FPGAEncoderHandle* fpgaEncoderHandle,
+                          HAL_CounterHandle* counterHandle);
+}  // namespace hal
+
+extern "C" {
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    initialize
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_DMAJNI_initialize
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  auto handle = HAL_InitializeDMA(&status);
+  CheckStatusForceThrow(env, status);
+  return handle;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    free
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_free
+  (JNIEnv* env, jclass, jint handle)
+{
+  HAL_FreeDMA(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    setPause
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_setPause
+  (JNIEnv* env, jclass, jint handle, jboolean pause)
+{
+  int32_t status = 0;
+  HAL_SetDMAPause(handle, pause, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    setTimedTrigger
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_setTimedTrigger
+  (JNIEnv* env, jclass, jint handle, jdouble seconds)
+{
+  int32_t status = 0;
+  HAL_SetDMATimedTrigger(handle, seconds, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    setTimedTriggerCycles
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_setTimedTriggerCycles
+  (JNIEnv* env, jclass, jint handle, jint cycles)
+{
+  int32_t status = 0;
+  HAL_SetDMATimedTriggerCycles(handle, static_cast<uint32_t>(cycles), &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addEncoder
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addEncoder
+  (JNIEnv* env, jclass, jint handle, jint encoderHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMAEncoder(handle, encoderHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addEncoderPeriod
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addEncoderPeriod
+  (JNIEnv* env, jclass, jint handle, jint encoderHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMAEncoderPeriod(handle, encoderHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addCounter
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addCounter
+  (JNIEnv* env, jclass, jint handle, jint counterHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMACounter(handle, counterHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addCounterPeriod
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addCounterPeriod
+  (JNIEnv* env, jclass, jint handle, jint counterHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMACounterPeriod(handle, counterHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addDutyCycle
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addDutyCycle
+  (JNIEnv* env, jclass, jint handle, jint dutyCycleHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMADutyCycle(handle, dutyCycleHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addDigitalSource
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addDigitalSource
+  (JNIEnv* env, jclass, jint handle, jint digitalSourceHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMADigitalSource(handle, digitalSourceHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addAnalogInput
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addAnalogInput
+  (JNIEnv* env, jclass, jint handle, jint analogInputHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMAAnalogInput(handle, analogInputHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addAveragedAnalogInput
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addAveragedAnalogInput
+  (JNIEnv* env, jclass, jint handle, jint analogInputHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMAAveragedAnalogInput(handle, analogInputHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    addAnalogAccumulator
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_addAnalogAccumulator
+  (JNIEnv* env, jclass, jint handle, jint analogInputHandle)
+{
+  int32_t status = 0;
+  HAL_AddDMAAnalogAccumulator(handle, analogInputHandle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    setExternalTrigger
+ * Signature: (IIIZZ)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_DMAJNI_setExternalTrigger
+  (JNIEnv* env, jclass, jint handle, jint digitalSourceHandle,
+   jint analogTriggerType, jboolean rising, jboolean falling)
+{
+  int32_t status = 0;
+  int32_t idx = HAL_SetDMAExternalTrigger(
+      handle, digitalSourceHandle,
+      static_cast<HAL_AnalogTriggerType>(analogTriggerType), rising, falling,
+      &status);
+  CheckStatus(env, status);
+  return idx;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    clearSensors
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_clearSensors
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  HAL_ClearDMASensors(handle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    clearExternalTriggers
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_clearExternalTriggers
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  HAL_ClearDMAExternalTriggers(handle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    startDMA
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_startDMA
+  (JNIEnv* env, jclass, jint handle, jint queueDepth)
+{
+  int32_t status = 0;
+  HAL_StartDMA(handle, queueDepth, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    stopDMA
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_DMAJNI_stopDMA
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  HAL_StopDMA(handle, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    readDMA
+ * Signature: (ID[I[I)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_first_hal_DMAJNI_readDMA
+  (JNIEnv* env, jclass, jint handle, jdouble timeoutSeconds, jintArray buf,
+   jintArray store)
+{
+  int32_t status = 0;
+  HAL_DMASample dmaSample;
+  std::memset(&dmaSample, 0, sizeof(dmaSample));
+  int32_t remaining = 0;
+  HAL_DMAReadStatus readStatus =
+      HAL_ReadDMA(handle, &dmaSample, timeoutSeconds, &remaining, &status);
+  CheckStatus(env, status);
+
+  static_assert(sizeof(uint32_t) == sizeof(jint), "Java ints must be 32 bits");
+
+  env->SetIntArrayRegion(buf, 0, dmaSample.captureSize,
+                         reinterpret_cast<jint*>(dmaSample.readBuffer));
+
+  int32_t* nativeArr =
+      static_cast<int32_t*>(env->GetPrimitiveArrayCritical(store, nullptr));
+
+  std::copy_n(
+      dmaSample.channelOffsets,
+      sizeof(dmaSample.channelOffsets) / sizeof(dmaSample.channelOffsets[0]),
+      nativeArr);
+  nativeArr[22] = static_cast<int32_t>(dmaSample.captureSize);
+  nativeArr[23] = static_cast<int32_t>(dmaSample.triggerChannels);
+  nativeArr[24] = remaining;
+  nativeArr[25] = readStatus;
+
+  env->ReleasePrimitiveArrayCritical(store, nativeArr, JNI_ABORT);
+
+  return dmaSample.timeStamp;
+}
+
+// TODO sync these up
+enum DMAOffsetConstants {
+  kEnable_AI0_Low = 0,
+  kEnable_AI0_High = 1,
+  kEnable_AIAveraged0_Low = 2,
+  kEnable_AIAveraged0_High = 3,
+  kEnable_AI1_Low = 4,
+  kEnable_AI1_High = 5,
+  kEnable_AIAveraged1_Low = 6,
+  kEnable_AIAveraged1_High = 7,
+  kEnable_Accumulator0 = 8,
+  kEnable_Accumulator1 = 9,
+  kEnable_DI = 10,
+  kEnable_AnalogTriggers = 11,
+  kEnable_Counters_Low = 12,
+  kEnable_Counters_High = 13,
+  kEnable_CounterTimers_Low = 14,
+  kEnable_CounterTimers_High = 15,
+  kEnable_Encoders_Low = 16,
+  kEnable_Encoders_High = 17,
+  kEnable_EncoderTimers_Low = 18,
+  kEnable_EncoderTimers_High = 19,
+  kEnable_DutyCycle_Low = 20,
+  kEnable_DutyCycle_High = 21,
+};
+
+/*
+ * Class:     edu_wpi_first_hal_DMAJNI
+ * Method:    getSensorReadData
+ * Signature: (I)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL
+Java_edu_wpi_first_hal_DMAJNI_getSensorReadData
+  (JNIEnv* env, jclass, jint handle)
+{
+  HAL_Handle halHandle = static_cast<HAL_Handle>(handle);
+
+  // Check for encoder/counter handle
+  HAL_FPGAEncoderHandle fpgaEncoderHandle = 0;
+  HAL_CounterHandle counterHandle = 0;
+  bool validEncoderHandle =
+      hal::GetEncoderBaseHandle(halHandle, &fpgaEncoderHandle, &counterHandle);
+
+  if (validEncoderHandle) {
+    if (counterHandle != HAL_kInvalidHandle) {
+      int32_t cindex = getHandleIndex(counterHandle);
+      if (cindex < 4) {
+        return CreateDMABaseStore(env, kEnable_Counters_Low, cindex);
+      } else {
+        return CreateDMABaseStore(env, kEnable_Counters_High, cindex - 4);
+      }
+    } else {
+      int32_t cindex = getHandleIndex(fpgaEncoderHandle);
+      if (cindex < 4) {
+        return CreateDMABaseStore(env, kEnable_Encoders_Low, cindex);
+      } else {
+        return CreateDMABaseStore(env, kEnable_Encoders_High, cindex - 4);
+      }
+    }
+  }
+
+  HAL_HandleEnum handleType = getHandleType(halHandle);
+  int32_t index = getHandleIndex(halHandle);
+  if (handleType == HAL_HandleEnum::DIO) {
+    return CreateDMABaseStore(env, kEnable_DI, index);
+  } else if (handleType == HAL_HandleEnum::AnalogTrigger) {
+    return CreateDMABaseStore(env, kEnable_AnalogTriggers, index);
+  } else if (handleType == HAL_HandleEnum::AnalogInput) {
+    if (index < 4) {
+      return CreateDMABaseStore(env, kEnable_AI0_Low, index);
+    } else {
+      return CreateDMABaseStore(env, kEnable_AI0_High, index - 4);
+    }
+  } else if (handleType == HAL_HandleEnum::DutyCycle) {
+    if (index < 4) {
+      return CreateDMABaseStore(env, kEnable_DutyCycle_Low, index);
+    } else {
+      return CreateDMABaseStore(env, kEnable_DutyCycle_High, index - 4);
+    }
+  } else {
+    return nullptr;
+  }
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/DigitalGlitchFilterJNI.cpp b/hal/src/main/native/cpp/jni/DigitalGlitchFilterJNI.cpp
index cfb504d..762f7fb 100644
--- a/hal/src/main/native/cpp/jni/DigitalGlitchFilterJNI.cpp
+++ b/hal/src/main/native/cpp/jni/DigitalGlitchFilterJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/DutyCycleJNI.cpp b/hal/src/main/native/cpp/jni/DutyCycleJNI.cpp
index b191374..96cc27b 100644
--- a/hal/src/main/native/cpp/jni/DutyCycleJNI.cpp
+++ b/hal/src/main/native/cpp/jni/DutyCycleJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/EncoderJNI.cpp b/hal/src/main/native/cpp/jni/EncoderJNI.cpp
index 11686a6..f93e064 100644
--- a/hal/src/main/native/cpp/jni/EncoderJNI.cpp
+++ b/hal/src/main/native/cpp/jni/EncoderJNI.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 <jni.h>
 
@@ -270,10 +267,6 @@
 {
   int32_t status = 0;
   HAL_SetEncoderSamplesToAverage((HAL_EncoderHandle)id, value, &status);
-  if (status == PARAMETER_OUT_OF_RANGE) {
-    ThrowBoundaryException(env, value, 1, 127);
-    return;
-  }
   CheckStatus(env, status);
 }
 
diff --git a/hal/src/main/native/cpp/jni/HAL.cpp b/hal/src/main/native/cpp/jni/HAL.cpp
index 3d736bf..4e26032 100644
--- a/hal/src/main/native/cpp/jni/HAL.cpp
+++ b/hal/src/main/native/cpp/jni/HAL.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/HAL.h"
 
@@ -12,6 +9,7 @@
 #include <cassert>
 #include <cstring>
 
+#include <fmt/format.h>
 #include <wpi/jni_util.h>
 
 #include "HALUtil.h"
@@ -86,6 +84,30 @@
 
 /*
  * Class:     edu_wpi_first_hal_HAL
+ * Method:    simPeriodicBeforeNative
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_simPeriodicBeforeNative
+  (JNIEnv*, jclass)
+{
+  HAL_SimPeriodicBefore();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
+ * Method:    simPeriodicAfterNative
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_HAL_simPeriodicAfterNative
+  (JNIEnv*, jclass)
+{
+  HAL_SimPeriodicAfter();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_HAL
  * Method:    observeUserProgramStarting
  * Signature: ()V
  */
@@ -172,7 +194,6 @@
   static_assert(sizeof(HAL_ControlWord) == sizeof(jint),
                 "Java int must match the size of control word");
   HAL_ControlWord controlWord;
-  std::memset(&controlWord, 0, sizeof(HAL_ControlWord));
   HAL_GetControlWord(&controlWord);
   jint retVal = 0;
   std::memcpy(&retVal, &controlWord, sizeof(HAL_ControlWord));
@@ -207,13 +228,11 @@
 
   jsize javaSize = env->GetArrayLength(axesArray);
   if (axes.count > javaSize) {
-    wpi::SmallString<128> errStr;
-    wpi::raw_svector_ostream oss{errStr};
-    oss << "Native array size larger then passed in java array size "
-        << "Native Size: " << static_cast<int>(axes.count)
-        << " Java Size: " << static_cast<int>(javaSize);
-
-    ThrowIllegalArgumentException(env, errStr.str());
+    ThrowIllegalArgumentException(
+        env,
+        fmt::format("Native array size larger then passed in java array "
+                    "size\nNative Size: {} Java Size: {}",
+                    static_cast<int>(axes.count), static_cast<int>(javaSize)));
     return 0;
   }
 
@@ -236,13 +255,11 @@
 
   jsize javaSize = env->GetArrayLength(povsArray);
   if (povs.count > javaSize) {
-    wpi::SmallString<128> errStr;
-    wpi::raw_svector_ostream oss{errStr};
-    oss << "Native array size larger then passed in java array size "
-        << "Native Size: " << static_cast<int>(povs.count)
-        << " Java Size: " << static_cast<int>(javaSize);
-
-    ThrowIllegalArgumentException(env, errStr.str());
+    ThrowIllegalArgumentException(
+        env,
+        fmt::format("Native array size larger then passed in java array "
+                    "size\nNative Size: {} Java Size: {}",
+                    static_cast<int>(povs.count), static_cast<int>(javaSize)));
     return 0;
   }
 
diff --git a/hal/src/main/native/cpp/jni/HALUtil.cpp b/hal/src/main/native/cpp/jni/HALUtil.cpp
index 2938f45..1070085 100644
--- a/hal/src/main/native/cpp/jni/HALUtil.cpp
+++ b/hal/src/main/native/cpp/jni/HALUtil.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 "HALUtil.h"
 
@@ -15,9 +12,8 @@
 #include <cstring>
 #include <string>
 
-#include <wpi/SmallString.h>
+#include <fmt/format.h>
 #include <wpi/jni_util.h>
-#include <wpi/raw_ostream.h>
 
 #include "edu_wpi_first_hal_HALUtil.h"
 #include "hal/CAN.h"
@@ -34,6 +30,12 @@
 #define kRIOStatusFeatureNotSupported (kRioStatusOffset - 193)
 #define kRIOStatusResourceNotInitialized -52010
 
+static_assert(edu_wpi_first_hal_HALUtil_RUNTIME_ROBORIO == HAL_Runtime_RoboRIO);
+static_assert(edu_wpi_first_hal_HALUtil_RUNTIME_ROBORIO2 ==
+              HAL_Runtime_RoboRIO2);
+static_assert(edu_wpi_first_hal_HALUtil_RUNTIME_SIMULATION ==
+              HAL_Runtime_Simulation);
+
 static JavaVM* jvm = nullptr;
 static JException illegalArgExCls;
 static JException boundaryExCls;
@@ -50,6 +52,7 @@
 static JClass accumulatorResultCls;
 static JClass canDataCls;
 static JClass halValueCls;
+static JClass baseStoreCls;
 
 static const JClassInit classes[] = {
     {"edu/wpi/first/hal/PWMConfigDataResult", &pwmConfigDataResultCls},
@@ -57,7 +60,8 @@
     {"edu/wpi/first/hal/MatchInfoData", &matchInfoDataCls},
     {"edu/wpi/first/hal/AccumulatorResult", &accumulatorResultCls},
     {"edu/wpi/first/hal/CANData", &canDataCls},
-    {"edu/wpi/first/hal/HALValue", &halValueCls}};
+    {"edu/wpi/first/hal/HALValue", &halValueCls},
+    {"edu/wpi/first/hal/DMAJNISample$BaseStore", &baseStoreCls}};
 
 static const JExceptionInit exceptions[] = {
     {"java/lang/IllegalArgumentException", &illegalArgExCls},
@@ -75,7 +79,7 @@
 
 namespace hal {
 
-void ThrowUncleanStatusException(JNIEnv* env, wpi::StringRef msg,
+void ThrowUncleanStatusException(JNIEnv* env, std::string_view msg,
                                  int32_t status) {
   static jmethodID func =
       env->GetMethodID(uncleanStatusExCls, "<init>", "(ILjava/lang/String;)V");
@@ -86,63 +90,64 @@
   env->Throw(static_cast<jthrowable>(exception));
 }
 
-void ThrowAllocationException(JNIEnv* env, int32_t minRange, int32_t maxRange,
-                              int32_t requestedValue, int32_t status) {
-  const char* message = HAL_GetErrorMessage(status);
-  wpi::SmallString<1024> buf;
-  wpi::raw_svector_ostream oss(buf);
-  oss << " Code: " << status << ". " << message
-      << ", Minimum Value: " << minRange << ", Maximum Value: " << maxRange
-      << ", Requested Value: " << requestedValue;
-  env->ThrowNew(allocationExCls, buf.c_str());
-  allocationExCls.Throw(env, buf.c_str());
+void ThrowAllocationException(JNIEnv* env, const char* lastError,
+                              int32_t status) {
+  allocationExCls.Throw(env,
+                        fmt::format("Code: {}\n{}", status, lastError).c_str());
 }
 
 void ThrowHalHandleException(JNIEnv* env, int32_t status) {
-  const char* message = HAL_GetErrorMessage(status);
-  wpi::SmallString<1024> buf;
-  wpi::raw_svector_ostream oss(buf);
-  oss << " Code: " << status << ". " << message;
-  halHandleExCls.Throw(env, buf.c_str());
+  const char* message = HAL_GetLastError(&status);
+  halHandleExCls.Throw(env,
+                       fmt::format(" Code: {}. {}", status, message).c_str());
 }
 
 void ReportError(JNIEnv* env, int32_t status, bool doThrow) {
-  if (status == 0) return;
+  if (status == 0) {
+    return;
+  }
+  const char* message = HAL_GetLastError(&status);
   if (status == HAL_HANDLE_ERROR) {
     ThrowHalHandleException(env, status);
+    return;
   }
-  const char* message = HAL_GetErrorMessage(status);
   if (doThrow && status < 0) {
-    wpi::SmallString<1024> buf;
-    wpi::raw_svector_ostream oss(buf);
-    oss << " Code: " << status << ". " << message;
-    ThrowUncleanStatusException(env, buf.c_str(), status);
+    ThrowUncleanStatusException(
+        env, fmt::format(" Code: {}. {}", status, message).c_str(), status);
   } else {
     std::string func;
     auto stack = GetJavaStackTrace(env, &func, "edu.wpi.first");
-    HAL_SendError(1, status, 0, message, func.c_str(), stack.c_str(), 1);
+    // Make a copy of message for safety, calling back into the HAL might
+    // invalidate the string.
+    std::string lastMessage{message};
+    HAL_SendError(1, status, 0, lastMessage.c_str(), func.c_str(),
+                  stack.c_str(), 1);
   }
 }
 
 void ThrowError(JNIEnv* env, int32_t status, int32_t minRange, int32_t maxRange,
                 int32_t requestedValue) {
-  if (status == 0) return;
+  if (status == 0) {
+    return;
+  }
+  const char* lastError = HAL_GetLastError(&status);
   if (status == NO_AVAILABLE_RESOURCES || status == RESOURCE_IS_ALLOCATED ||
       status == RESOURCE_OUT_OF_RANGE) {
-    ThrowAllocationException(env, minRange, maxRange, requestedValue, status);
+    ThrowAllocationException(env, lastError, status);
+    return;
   }
   if (status == HAL_HANDLE_ERROR) {
     ThrowHalHandleException(env, status);
+    return;
   }
-  const char* message = HAL_GetErrorMessage(status);
-  wpi::SmallString<1024> buf;
-  wpi::raw_svector_ostream oss(buf);
-  oss << " Code: " << status << ". " << message;
-  ThrowUncleanStatusException(env, buf.c_str(), status);
+  ThrowUncleanStatusException(
+      env, fmt::format(" Code: {}. {}", status, lastError).c_str(), status);
 }
 
 void ReportCANError(JNIEnv* env, int32_t status, int message_id) {
-  if (status >= 0) return;
+  if (status >= 0) {
+    return;
+  }
   switch (status) {
     case kRioStatusSuccess:
       // Everything is ok... don't throw.
@@ -150,9 +155,10 @@
     case HAL_ERR_CANSessionMux_InvalidBuffer:
     case kRIOStatusBufferInvalidSize: {
       static jmethodID invalidBufConstruct = nullptr;
-      if (!invalidBufConstruct)
+      if (!invalidBufConstruct) {
         invalidBufConstruct =
             env->GetMethodID(canInvalidBufferExCls, "<init>", "()V");
+      }
       jobject exception =
           env->NewObject(canInvalidBufferExCls, invalidBufConstruct);
       env->Throw(static_cast<jthrowable>(exception));
@@ -161,9 +167,10 @@
     case HAL_ERR_CANSessionMux_MessageNotFound:
     case kRIOStatusOperationTimedOut: {
       static jmethodID messageNotFoundConstruct = nullptr;
-      if (!messageNotFoundConstruct)
+      if (!messageNotFoundConstruct) {
         messageNotFoundConstruct =
             env->GetMethodID(canMessageNotFoundExCls, "<init>", "()V");
+      }
       jobject exception =
           env->NewObject(canMessageNotFoundExCls, messageNotFoundConstruct);
       env->Throw(static_cast<jthrowable>(exception));
@@ -171,48 +178,47 @@
     }
     case HAL_ERR_CANSessionMux_NotAllowed:
     case kRIOStatusFeatureNotSupported: {
-      wpi::SmallString<100> buf;
-      wpi::raw_svector_ostream oss(buf);
-      oss << "MessageID = " << message_id;
-      canMessageNotAllowedExCls.Throw(env, buf.c_str());
+      canMessageNotAllowedExCls.Throw(
+          env, fmt::format("MessageID = {}", message_id).c_str());
       break;
     }
     case HAL_ERR_CANSessionMux_NotInitialized:
     case kRIOStatusResourceNotInitialized: {
       static jmethodID notInitConstruct = nullptr;
-      if (!notInitConstruct)
+      if (!notInitConstruct) {
         notInitConstruct =
             env->GetMethodID(canNotInitializedExCls, "<init>", "()V");
+      }
       jobject exception =
           env->NewObject(canNotInitializedExCls, notInitConstruct);
       env->Throw(static_cast<jthrowable>(exception));
       break;
     }
     default: {
-      wpi::SmallString<100> buf;
-      wpi::raw_svector_ostream oss(buf);
-      oss << "Fatal status code detected: " << status;
-      uncleanStatusExCls.Throw(env, buf.c_str());
+      uncleanStatusExCls.Throw(
+          env, fmt::format("Fatal status code detected: {}", status).c_str());
       break;
     }
   }
 }
 
-void ThrowIllegalArgumentException(JNIEnv* env, wpi::StringRef msg) {
+void ThrowIllegalArgumentException(JNIEnv* env, std::string_view msg) {
   illegalArgExCls.Throw(env, msg);
 }
 
 void ThrowBoundaryException(JNIEnv* env, double value, double lower,
                             double upper) {
   static jmethodID getMessage = nullptr;
-  if (!getMessage)
+  if (!getMessage) {
     getMessage = env->GetStaticMethodID(boundaryExCls, "getMessage",
                                         "(DDD)Ljava/lang/String;");
+  }
 
   static jmethodID constructor = nullptr;
-  if (!constructor)
+  if (!constructor) {
     constructor =
         env->GetMethodID(boundaryExCls, "<init>", "(Ljava/lang/String;)V");
+  }
 
   jobject msg = env->CallStaticObjectMethod(
       boundaryExCls, getMessage, static_cast<jdouble>(value),
@@ -226,9 +232,10 @@
                                   int32_t deadbandMinPwm, int32_t minPwm) {
   static jmethodID constructor =
       env->GetMethodID(pwmConfigDataResultCls, "<init>", "(IIIII)V");
-  return env->NewObject(pwmConfigDataResultCls, constructor, (jint)maxPwm,
-                        (jint)deadbandMaxPwm, (jint)centerPwm,
-                        (jint)deadbandMinPwm, (jint)minPwm);
+  return env->NewObject(
+      pwmConfigDataResultCls, constructor, static_cast<jint>(maxPwm),
+      static_cast<jint>(deadbandMaxPwm), static_cast<jint>(centerPwm),
+      static_cast<jint>(deadbandMinPwm), static_cast<jint>(minPwm));
 }
 
 void SetCanStatusObject(JNIEnv* env, jobject canStatus,
@@ -237,9 +244,11 @@
                         uint32_t transmitErrorCount) {
   static jmethodID func =
       env->GetMethodID(canStatusCls, "setStatus", "(DIIII)V");
-  env->CallVoidMethod(canStatus, func, (jdouble)percentBusUtilization,
-                      (jint)busOffCount, (jint)txFullCount,
-                      (jint)receiveErrorCount, (jint)transmitErrorCount);
+  env->CallVoidMethod(
+      canStatus, func, static_cast<jdouble>(percentBusUtilization),
+      static_cast<jint>(busOffCount), static_cast<jint>(txFullCount),
+      static_cast<jint>(receiveErrorCount),
+      static_cast<jint>(transmitErrorCount));
 }
 
 void SetMatchInfoObject(JNIEnv* env, jobject matchStatus,
@@ -250,11 +259,12 @@
 
   env->CallVoidMethod(
       matchStatus, func, MakeJString(env, matchInfo.eventName),
-      MakeJString(env, wpi::StringRef{reinterpret_cast<const char*>(
-                                          matchInfo.gameSpecificMessage),
-                                      matchInfo.gameSpecificMessageSize}),
-      (jint)matchInfo.matchNumber, (jint)matchInfo.replayNumber,
-      (jint)matchInfo.matchType);
+      MakeJString(env,
+                  {reinterpret_cast<const char*>(matchInfo.gameSpecificMessage),
+                   matchInfo.gameSpecificMessageSize}),
+      static_cast<jint>(matchInfo.matchNumber),
+      static_cast<jint>(matchInfo.replayNumber),
+      static_cast<jint>(matchInfo.matchType));
 }
 
 void SetAccumulatorResultObject(JNIEnv* env, jobject accumulatorResult,
@@ -262,15 +272,16 @@
   static jmethodID func =
       env->GetMethodID(accumulatorResultCls, "set", "(JJ)V");
 
-  env->CallVoidMethod(accumulatorResult, func, (jlong)value, (jlong)count);
+  env->CallVoidMethod(accumulatorResult, func, static_cast<jlong>(value),
+                      static_cast<jlong>(count));
 }
 
 jbyteArray SetCANDataObject(JNIEnv* env, jobject canData, int32_t length,
                             uint64_t timestamp) {
   static jmethodID func = env->GetMethodID(canDataCls, "setData", "(IJ)[B");
 
-  jbyteArray retVal = static_cast<jbyteArray>(
-      env->CallObjectMethod(canData, func, (jint)length, (jlong)timestamp));
+  jbyteArray retVal = static_cast<jbyteArray>(env->CallObjectMethod(
+      canData, func, static_cast<jint>(length), static_cast<jlong>(timestamp)));
   return retVal;
 }
 
@@ -298,11 +309,18 @@
     default:
       break;
   }
-  return env->CallStaticObjectMethod(halValueCls, fromNative, (jint)value.type,
-                                     value1, value2);
+  return env->CallStaticObjectMethod(
+      halValueCls, fromNative, static_cast<jint>(value.type), value1, value2);
 }
 
-JavaVM* GetJVM() { return jvm; }
+jobject CreateDMABaseStore(JNIEnv* env, jint valueType, jint index) {
+  static jmethodID ctor = env->GetMethodID(baseStoreCls, "<init>", "(II)V");
+  return env->NewObject(baseStoreCls, ctor, valueType, index);
+}
+
+JavaVM* GetJVM() {
+  return jvm;
+}
 
 namespace sim {
 jint SimOnLoad(JavaVM* vm, void* reserved);
@@ -322,17 +340,22 @@
   jvm = vm;
 
   JNIEnv* env;
-  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
     return JNI_ERR;
+  }
 
   for (auto& c : classes) {
     *c.cls = JClass(env, c.name);
-    if (!*c.cls) return JNI_ERR;
+    if (!*c.cls) {
+      return JNI_ERR;
+    }
   }
 
   for (auto& c : exceptions) {
     *c.cls = JException(env, c.name);
-    if (!*c.cls) return JNI_ERR;
+    if (!*c.cls) {
+      return JNI_ERR;
+    }
   }
 
   return sim::SimOnLoad(vm, reserved);
@@ -342,8 +365,9 @@
   sim::SimOnUnload(vm, reserved);
 
   JNIEnv* env;
-  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
     return;
+  }
   // Delete global references
 
   for (auto& c : classes) {
diff --git a/hal/src/main/native/cpp/jni/HALUtil.h b/hal/src/main/native/cpp/jni/HALUtil.h
index 0a192da..2afe595 100644
--- a/hal/src/main/native/cpp/jni/HALUtil.h
+++ b/hal/src/main/native/cpp/jni/HALUtil.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.
 
 #ifndef HAL_HAL_SRC_MAIN_NATIVE_CPP_JNI_HALUTIL_H_
 #define HAL_HAL_SRC_MAIN_NATIVE_CPP_JNI_HALUTIL_H_
@@ -11,7 +8,7 @@
 #include <jni.h>
 #include <stdint.h>
 
-#include <wpi/StringRef.h>
+#include <string_view>
 
 struct HAL_MatchInfo;
 struct HAL_Value;
@@ -24,29 +21,37 @@
                 int32_t requestedValue);
 
 inline bool CheckStatus(JNIEnv* env, int32_t status, bool doThrow = true) {
-  if (status != 0) ReportError(env, status, doThrow);
+  if (status != 0) {
+    ReportError(env, status, doThrow);
+  }
   return status == 0;
 }
 
 inline bool CheckStatusRange(JNIEnv* env, int32_t status, int32_t minRange,
                              int32_t maxRange, int32_t requestedValue) {
-  if (status != 0) ThrowError(env, status, minRange, maxRange, requestedValue);
+  if (status != 0) {
+    ThrowError(env, status, minRange, maxRange, requestedValue);
+  }
   return status == 0;
 }
 
 inline bool CheckStatusForceThrow(JNIEnv* env, int32_t status) {
-  if (status != 0) ThrowError(env, status, 0, 0, 0);
+  if (status != 0) {
+    ThrowError(env, status, 0, 0, 0);
+  }
   return status == 0;
 }
 
 void ReportCANError(JNIEnv* env, int32_t status, int32_t message_id);
 
 inline bool CheckCANStatus(JNIEnv* env, int32_t status, int32_t message_id) {
-  if (status != 0) ReportCANError(env, status, message_id);
+  if (status != 0) {
+    ReportCANError(env, status, message_id);
+  }
   return status == 0;
 }
 
-void ThrowIllegalArgumentException(JNIEnv* env, wpi::StringRef msg);
+void ThrowIllegalArgumentException(JNIEnv* env, std::string_view msg);
 void ThrowBoundaryException(JNIEnv* env, double value, double lower,
                             double upper);
 
@@ -70,6 +75,8 @@
 
 jobject CreateHALValue(JNIEnv* env, const HAL_Value& value);
 
+jobject CreateDMABaseStore(JNIEnv* env, jint valueType, jint index);
+
 JavaVM* GetJVM();
 
 }  // namespace hal
diff --git a/hal/src/main/native/cpp/jni/I2CJNI.cpp b/hal/src/main/native/cpp/jni/I2CJNI.cpp
index de27df6..b605b95 100644
--- a/hal/src/main/native/cpp/jni/I2CJNI.cpp
+++ b/hal/src/main/native/cpp/jni/I2CJNI.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 <jni.h>
 
@@ -45,7 +42,7 @@
    jbyte sendSize, jobject dataReceived, jbyte receiveSize)
 {
   uint8_t* dataToSendPtr = nullptr;
-  if (dataToSend != 0) {
+  if (dataToSend != nullptr) {
     dataToSendPtr =
         reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataToSend));
   }
@@ -91,7 +88,7 @@
 {
   uint8_t* dataToSendPtr = nullptr;
 
-  if (dataToSend != 0) {
+  if (dataToSend != nullptr) {
     dataToSendPtr =
         reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataToSend));
   }
diff --git a/hal/src/main/native/cpp/jni/InterruptJNI.cpp b/hal/src/main/native/cpp/jni/InterruptJNI.cpp
index d18ef27..ed56ce5 100644
--- a/hal/src/main/native/cpp/jni/InterruptJNI.cpp
+++ b/hal/src/main/native/cpp/jni/InterruptJNI.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 <jni.h>
 
@@ -20,108 +17,19 @@
 
 using namespace hal;
 
-// Thread where callbacks are actually performed.
-//
-// JNI's AttachCurrentThread() creates a Java Thread object on every
-// invocation, which is both time inefficient and causes issues with Eclipse
-// (which tries to keep a thread list up-to-date and thus gets swamped).
-//
-// Instead, this class attaches just once.  When a hardware notification
-// occurs, a condition variable wakes up this thread and this thread actually
-// makes the call into Java.
-//
-// We don't want to use a FIFO here. If the user code takes too long to
-// process, we will just ignore the redundant wakeup.
-class InterruptThreadJNI : public wpi::SafeThread {
- public:
-  void Main();
-
-  bool m_notify = false;
-  uint32_t m_mask = 0;
-  jobject m_func = nullptr;
-  jmethodID m_mid;
-  jobject m_param = nullptr;
-};
-
-class InterruptJNI : public wpi::SafeThreadOwner<InterruptThreadJNI> {
- public:
-  void SetFunc(JNIEnv* env, jobject func, jmethodID mid, jobject param);
-
-  void Notify(uint32_t mask) {
-    auto thr = GetThread();
-    if (!thr) return;
-    thr->m_notify = true;
-    thr->m_mask = mask;
-    thr->m_cond.notify_one();
-  }
-};
-
-void InterruptJNI::SetFunc(JNIEnv* env, jobject func, jmethodID mid,
-                           jobject param) {
-  auto thr = GetThread();
-  if (!thr) return;
-  // free global references
-  if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
-  if (thr->m_param) env->DeleteGlobalRef(thr->m_param);
-  // create global references
-  thr->m_func = env->NewGlobalRef(func);
-  thr->m_param = param ? env->NewGlobalRef(param) : nullptr;
-  thr->m_mid = mid;
-}
-
-void InterruptThreadJNI::Main() {
-  JNIEnv* env;
-  JavaVMAttachArgs args;
-  args.version = JNI_VERSION_1_2;
-  args.name = const_cast<char*>("Interrupt");
-  args.group = nullptr;
-  jint rs = GetJVM()->AttachCurrentThreadAsDaemon(
-      reinterpret_cast<void**>(&env), &args);
-  if (rs != JNI_OK) return;
-
-  std::unique_lock lock(m_mutex);
-  while (m_active) {
-    m_cond.wait(lock, [&] { return !m_active || m_notify; });
-    if (!m_active) break;
-    m_notify = false;
-    if (!m_func) continue;
-    jobject func = m_func;
-    jmethodID mid = m_mid;
-    uint32_t mask = m_mask;
-    jobject param = m_param;
-    lock.unlock();  // don't hold mutex during callback execution
-    env->CallVoidMethod(func, mid, static_cast<jint>(mask), param);
-    if (env->ExceptionCheck()) {
-      env->ExceptionDescribe();
-      env->ExceptionClear();
-    }
-    lock.lock();
-  }
-
-  // free global references
-  if (m_func) env->DeleteGlobalRef(m_func);
-  if (m_param) env->DeleteGlobalRef(m_param);
-
-  GetJVM()->DetachCurrentThread();
-}
-
-void interruptHandler(uint32_t mask, void* param) {
-  static_cast<InterruptJNI*>(param)->Notify(mask);
-}
-
 extern "C" {
 
 /*
  * Class:     edu_wpi_first_hal_InterruptJNI
  * Method:    initializeInterrupts
- * Signature: (Z)I
+ * Signature: ()I
  */
 JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_InterruptJNI_initializeInterrupts
-  (JNIEnv* env, jclass, jboolean watcher)
+  (JNIEnv* env, jclass)
 {
   int32_t status = 0;
-  HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(watcher, &status);
+  HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(&status);
 
   CheckStatusForceThrow(env, status);
   return (jint)interrupt;
@@ -136,14 +44,7 @@
 Java_edu_wpi_first_hal_InterruptJNI_cleanInterrupts
   (JNIEnv* env, jclass, jint interruptHandle)
 {
-  int32_t status = 0;
-  auto param =
-      HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle, &status);
-  if (param) {
-    delete static_cast<InterruptJNI*>(param);
-  }
-
-  // ignore status, as an invalid handle just needs to be ignored.
+  HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle);
 }
 
 /*
@@ -166,36 +67,6 @@
 
 /*
  * Class:     edu_wpi_first_hal_InterruptJNI
- * Method:    enableInterrupts
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_InterruptJNI_enableInterrupts
-  (JNIEnv* env, jclass, jint interruptHandle)
-{
-  int32_t status = 0;
-  HAL_EnableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
-
-  CheckStatus(env, status);
-}
-
-/*
- * Class:     edu_wpi_first_hal_InterruptJNI
- * Method:    disableInterrupts
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_InterruptJNI_disableInterrupts
-  (JNIEnv* env, jclass, jint interruptHandle)
-{
-  int32_t status = 0;
-  HAL_DisableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
-
-  CheckStatus(env, status);
-}
-
-/*
- * Class:     edu_wpi_first_hal_InterruptJNI
  * Method:    readInterruptRisingTimestamp
  * Signature: (I)J
  */
@@ -248,37 +119,6 @@
 
 /*
  * Class:     edu_wpi_first_hal_InterruptJNI
- * Method:    attachInterruptHandler
- * Signature: (ILjava/lang/Object;Ljava/lang/Object;)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_InterruptJNI_attachInterruptHandler
-  (JNIEnv* env, jclass, jint interruptHandle, jobject handler, jobject param)
-{
-  jclass cls = env->GetObjectClass(handler);
-  if (cls == 0) {
-    assert(false);
-    return;
-  }
-  jmethodID mid = env->GetMethodID(cls, "apply", "(ILjava/lang/Object;)V");
-  if (mid == 0) {
-    assert(false);
-    return;
-  }
-
-  InterruptJNI* intr = new InterruptJNI;
-  intr->Start();
-  intr->SetFunc(env, handler, mid, param);
-
-  int32_t status = 0;
-  HAL_AttachInterruptHandler((HAL_InterruptHandle)interruptHandle,
-                             interruptHandler, intr, &status);
-
-  CheckStatus(env, status);
-}
-
-/*
- * Class:     edu_wpi_first_hal_InterruptJNI
  * Method:    setInterruptUpSourceEdge
  * Signature: (IZZ)V
  */
diff --git a/hal/src/main/native/cpp/jni/NotifierJNI.cpp b/hal/src/main/native/cpp/jni/NotifierJNI.cpp
index ed0b324..4e7069e 100644
--- a/hal/src/main/native/cpp/jni/NotifierJNI.cpp
+++ b/hal/src/main/native/cpp/jni/NotifierJNI.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 <jni.h>
 
@@ -41,6 +38,19 @@
 
 /*
  * Class:     edu_wpi_first_hal_NotifierJNI
+ * Method:    setHALThreadPriority
+ * Signature: (ZI)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_NotifierJNI_setHALThreadPriority
+  (JNIEnv* env, jclass, jboolean realTime, jint priority)
+{
+  int32_t status = 0;
+  return HAL_SetNotifierThreadPriority(realTime, priority, &status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_NotifierJNI
  * Method:    setNotifierName
  * Signature: (ILjava/lang/String;)V
  */
diff --git a/hal/src/main/native/cpp/jni/PDPJNI.cpp b/hal/src/main/native/cpp/jni/PDPJNI.cpp
deleted file mode 100644
index bb28fdf..0000000
--- a/hal/src/main/native/cpp/jni/PDPJNI.cpp
+++ /dev/null
@@ -1,193 +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 "HALUtil.h"
-#include "edu_wpi_first_hal_PDPJNI.h"
-#include "hal/PDP.h"
-#include "hal/Ports.h"
-
-using namespace hal;
-
-extern "C" {
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    initializePDP
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_PDPJNI_initializePDP
-  (JNIEnv* env, jclass, jint module)
-{
-  int32_t status = 0;
-  auto handle = HAL_InitializePDP(module, &status);
-  CheckStatusRange(env, status, 0, HAL_GetNumPDPModules(), module);
-  return static_cast<jint>(handle);
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    checkPDPChannel
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_PDPJNI_checkPDPChannel
-  (JNIEnv* env, jclass, jint channel)
-{
-  return HAL_CheckPDPChannel(channel);
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    checkPDPModule
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_PDPJNI_checkPDPModule
-  (JNIEnv* env, jclass, jint module)
-{
-  return HAL_CheckPDPModule(module);
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    getPDPTemperature
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_PDPJNI_getPDPTemperature
-  (JNIEnv* env, jclass, jint handle)
-{
-  int32_t status = 0;
-  double temperature = HAL_GetPDPTemperature(handle, &status);
-  CheckStatus(env, status, false);
-  return temperature;
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    getPDPVoltage
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_PDPJNI_getPDPVoltage
-  (JNIEnv* env, jclass, jint handle)
-{
-  int32_t status = 0;
-  double voltage = HAL_GetPDPVoltage(handle, &status);
-  CheckStatus(env, status, false);
-  return voltage;
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    getPDPChannelCurrent
- * Signature: (BI)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_PDPJNI_getPDPChannelCurrent
-  (JNIEnv* env, jclass, jbyte channel, jint handle)
-{
-  int32_t status = 0;
-  double current = HAL_GetPDPChannelCurrent(handle, channel, &status);
-  CheckStatus(env, status, false);
-  return current;
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    getPDPAllCurrents
- * Signature: (I[D)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_PDPJNI_getPDPAllCurrents
-  (JNIEnv* env, jclass, jint handle, jdoubleArray jarr)
-{
-  double storage[16];
-  int32_t status = 0;
-  HAL_GetPDPAllChannelCurrents(handle, storage, &status);
-  if (!CheckStatus(env, status, false)) {
-    return;
-  }
-
-  env->SetDoubleArrayRegion(jarr, 0, 16, storage);
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    getPDPTotalCurrent
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_PDPJNI_getPDPTotalCurrent
-  (JNIEnv* env, jclass, jint handle)
-{
-  int32_t status = 0;
-  double current = HAL_GetPDPTotalCurrent(handle, &status);
-  CheckStatus(env, status, false);
-  return current;
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    getPDPTotalPower
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_PDPJNI_getPDPTotalPower
-  (JNIEnv* env, jclass, jint handle)
-{
-  int32_t status = 0;
-  double power = HAL_GetPDPTotalPower(handle, &status);
-  CheckStatus(env, status, false);
-  return power;
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    getPDPTotalEnergy
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_PDPJNI_getPDPTotalEnergy
-  (JNIEnv* env, jclass, jint handle)
-{
-  int32_t status = 0;
-  double energy = HAL_GetPDPTotalEnergy(handle, &status);
-  CheckStatus(env, status, false);
-  return energy;
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    resetPDPTotalEnergy
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_PDPJNI_resetPDPTotalEnergy
-  (JNIEnv* env, jclass, jint handle)
-{
-  int32_t status = 0;
-  HAL_ResetPDPTotalEnergy(handle, &status);
-  CheckStatus(env, status, false);
-}
-
-/*
- * Class:     edu_wpi_first_hal_PDPJNI
- * Method:    clearPDPStickyFaults
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_PDPJNI_clearPDPStickyFaults
-  (JNIEnv* env, jclass, jint handle)
-{
-  int32_t status = 0;
-  HAL_ClearPDPStickyFaults(handle, &status);
-  CheckStatus(env, status, false);
-}
-
-}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/PWMJNI.cpp b/hal/src/main/native/cpp/jni/PWMJNI.cpp
index 085cd0c..e83f11b 100644
--- a/hal/src/main/native/cpp/jni/PWMJNI.cpp
+++ b/hal/src/main/native/cpp/jni/PWMJNI.cpp
@@ -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.
 
 #include <jni.h>
 
 #include <cassert>
 
+#include <wpi/jni_util.h>
+
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_PWMJNI.h"
 #include "hal/DIO.h"
@@ -30,9 +29,9 @@
   (JNIEnv* env, jclass, jint id)
 {
   int32_t status = 0;
-  auto pwm = HAL_InitializePWMPort((HAL_PortHandle)id, &status);
-  CheckStatusRange(env, status, 0, HAL_GetNumPWMChannels(),
-                   hal::getPortHandleChannel((HAL_PortHandle)id));
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
+  auto pwm = HAL_InitializePWMPort((HAL_PortHandle)id, stack.c_str(), &status);
+  CheckStatusForceThrow(env, status);
   return (jint)pwm;
 }
 
diff --git a/hal/src/main/native/cpp/jni/PortsJNI.cpp b/hal/src/main/native/cpp/jni/PortsJNI.cpp
index 65fabd4..9757f44 100644
--- a/hal/src/main/native/cpp/jni/PortsJNI.cpp
+++ b/hal/src/main/native/cpp/jni/PortsJNI.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 <jni.h>
 
@@ -200,53 +197,105 @@
 
 /*
  * Class:     edu_wpi_first_hal_PortsJNI
- * Method:    getNumPCMModules
+ * Method:    getNumCTREPCMModules
  * Signature: ()I
  */
 JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_PortsJNI_getNumPCMModules
+Java_edu_wpi_first_hal_PortsJNI_getNumCTREPCMModules
   (JNIEnv* env, jclass)
 {
-  jint value = HAL_GetNumPCMModules();
+  jint value = HAL_GetNumCTREPCMModules();
   return value;
 }
 
 /*
  * Class:     edu_wpi_first_hal_PortsJNI
- * Method:    getNumSolenoidChannels
+ * Method:    getNumCTRESolenoidChannels
  * Signature: ()I
  */
 JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_PortsJNI_getNumSolenoidChannels
+Java_edu_wpi_first_hal_PortsJNI_getNumCTRESolenoidChannels
   (JNIEnv* env, jclass)
 {
-  jint value = HAL_GetNumSolenoidChannels();
+  jint value = HAL_GetNumCTRESolenoidChannels();
   return value;
 }
 
 /*
  * Class:     edu_wpi_first_hal_PortsJNI
- * Method:    getNumPDPModules
+ * Method:    getNumCTREPDPModules
  * Signature: ()I
  */
 JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_PortsJNI_getNumPDPModules
+Java_edu_wpi_first_hal_PortsJNI_getNumCTREPDPModules
   (JNIEnv* env, jclass)
 {
-  jint value = HAL_GetNumPDPModules();
+  jint value = HAL_GetNumCTREPDPModules();
   return value;
 }
 
 /*
  * Class:     edu_wpi_first_hal_PortsJNI
- * Method:    getNumPDPChannels
+ * Method:    getNumCTREPDPChannels
  * Signature: ()I
  */
 JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_PortsJNI_getNumPDPChannels
+Java_edu_wpi_first_hal_PortsJNI_getNumCTREPDPChannels
   (JNIEnv* env, jclass)
 {
-  jint value = HAL_GetNumPDPChannels();
+  jint value = HAL_GetNumCTREPDPChannels();
+  return value;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumREVPDHModules
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PortsJNI_getNumREVPDHModules
+  (JNIEnv* env, jclass)
+{
+  jint value = HAL_GetNumREVPDHModules();
+  return value;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumREVPDHChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PortsJNI_getNumREVPDHChannels
+  (JNIEnv* env, jclass)
+{
+  jint value = HAL_GetNumREVPDHChannels();
+  return value;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumREVPHModules
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PortsJNI_getNumREVPHModules
+  (JNIEnv* env, jclass)
+{
+  jint value = HAL_GetNumREVPHModules();
+  return value;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PortsJNI
+ * Method:    getNumREVPHChannels
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PortsJNI_getNumREVPHChannels
+  (JNIEnv* env, jclass)
+{
+  jint value = HAL_GetNumREVPHChannels();
   return value;
 }
 }  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/PowerDistributionJNI.cpp b/hal/src/main/native/cpp/jni/PowerDistributionJNI.cpp
new file mode 100644
index 0000000..b608458
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/PowerDistributionJNI.cpp
@@ -0,0 +1,295 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_PowerDistributionJNI.h"
+#include "hal/Ports.h"
+#include "hal/PowerDistribution.h"
+
+using namespace hal;
+
+static_assert(edu_wpi_first_hal_PowerDistributionJNI_AUTOMATIC_TYPE ==
+              HAL_PowerDistributionType::HAL_PowerDistributionType_kAutomatic);
+static_assert(edu_wpi_first_hal_PowerDistributionJNI_CTRE_TYPE ==
+              HAL_PowerDistributionType::HAL_PowerDistributionType_kCTRE);
+static_assert(edu_wpi_first_hal_PowerDistributionJNI_REV_TYPE ==
+              HAL_PowerDistributionType::HAL_PowerDistributionType_kRev);
+static_assert(edu_wpi_first_hal_PowerDistributionJNI_DEFAULT_MODULE ==
+              HAL_DEFAULT_POWER_DISTRIBUTION_MODULE);
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    initialize
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_initialize
+  (JNIEnv* env, jclass, jint module, jint type)
+{
+  int32_t status = 0;
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
+  auto handle = HAL_InitializePowerDistribution(
+      module, static_cast<HAL_PowerDistributionType>(type), stack.c_str(),
+      &status);
+  CheckStatusForceThrow(env, status);
+  return static_cast<jint>(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    free
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_free
+  (JNIEnv*, jclass, jint handle)
+{
+  HAL_CleanPowerDistribution(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getModuleNumber
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getModuleNumber
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetPowerDistributionModuleNumber(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    checkChannel
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_checkChannel
+  (JNIEnv* env, jclass, jint handle, jint channel)
+{
+  return HAL_CheckPowerDistributionChannel(handle, channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    checkModule
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_checkModule
+  (JNIEnv* env, jclass, jint module, jint type)
+{
+  return HAL_CheckPowerDistributionModule(
+      module, static_cast<HAL_PowerDistributionType>(type));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getType
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getType
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetPowerDistributionType(handle, &status);
+  CheckStatus(env, status);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getNumChannels
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getNumChannels
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetPowerDistributionNumChannels(handle, &status);
+  CheckStatus(env, status);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getTemperature
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getTemperature
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double temperature = HAL_GetPowerDistributionTemperature(handle, &status);
+  CheckStatus(env, status, false);
+  return temperature;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getVoltage
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double voltage = HAL_GetPowerDistributionVoltage(handle, &status);
+  CheckStatus(env, status, false);
+  return voltage;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getChannelCurrent
+ * Signature: (II)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getChannelCurrent
+  (JNIEnv* env, jclass, jint handle, jint channel)
+{
+  int32_t status = 0;
+  double current =
+      HAL_GetPowerDistributionChannelCurrent(handle, channel, &status);
+  CheckStatus(env, status, false);
+  return current;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getAllCurrents
+ * Signature: (I[D)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getAllCurrents
+  (JNIEnv* env, jclass, jint handle, jdoubleArray jarr)
+{
+  double storage[16];
+  int32_t status = 0;
+  // TODO fix me
+  HAL_GetPowerDistributionAllChannelCurrents(handle, storage, 16, &status);
+  if (!CheckStatus(env, status, false)) {
+    return;
+  }
+
+  env->SetDoubleArrayRegion(jarr, 0, 16, storage);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getTotalCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getTotalCurrent
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double current = HAL_GetPowerDistributionTotalCurrent(handle, &status);
+  CheckStatus(env, status, false);
+  return current;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getTotalPower
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getTotalPower
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double power = HAL_GetPowerDistributionTotalPower(handle, &status);
+  CheckStatus(env, status, false);
+  return power;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getTotalEnergy
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getTotalEnergy
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  double energy = HAL_GetPowerDistributionTotalEnergy(handle, &status);
+  CheckStatus(env, status, false);
+  return energy;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    resetTotalEnergy
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_resetTotalEnergy
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  HAL_ResetPowerDistributionTotalEnergy(handle, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    clearStickyFaults
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_clearStickyFaults
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  HAL_ClearPowerDistributionStickyFaults(handle, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    setSwitchableChannel
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_setSwitchableChannel
+  (JNIEnv* env, jclass, jint handle, jboolean enabled)
+{
+  int32_t status = 0;
+  HAL_SetPowerDistributionSwitchableChannel(handle, enabled, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerDistributionJNI
+ * Method:    getSwitchableChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_PowerDistributionJNI_getSwitchableChannel
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto state = HAL_GetPowerDistributionSwitchableChannel(handle, &status);
+  CheckStatus(env, status, false);
+  return state;
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/PowerJNI.cpp b/hal/src/main/native/cpp/jni/PowerJNI.cpp
index 6fc42b4..92b174d 100644
--- a/hal/src/main/native/cpp/jni/PowerJNI.cpp
+++ b/hal/src/main/native/cpp/jni/PowerJNI.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 <jni.h>
 
@@ -225,4 +222,33 @@
   return val;
 }
 
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    setBrownoutVoltage
+ * Signature: (D)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_PowerJNI_setBrownoutVoltage
+  (JNIEnv* env, jclass, jdouble brownoutVoltage)
+{
+  int32_t status = 0;
+  HAL_SetBrownoutVoltage(brownoutVoltage, &status);
+  CheckStatus(env, status);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_PowerJNI
+ * Method:    getBrownoutVoltage
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_PowerJNI_getBrownoutVoltage
+  (JNIEnv* env, jclass)
+{
+  int32_t status = 0;
+  double val = HAL_GetBrownoutVoltage(&status);
+  CheckStatus(env, status);
+  return val;
+}
+
 }  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/REVPHJNI.cpp b/hal/src/main/native/cpp/jni/REVPHJNI.cpp
new file mode 100644
index 0000000..3e99430
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/REVPHJNI.cpp
@@ -0,0 +1,191 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <jni.h>
+
+#include <wpi/jni_util.h>
+
+#include "HALUtil.h"
+#include "edu_wpi_first_hal_REVPHJNI.h"
+#include "hal/Ports.h"
+#include "hal/REVPH.h"
+#include "hal/handles/HandlesInternal.h"
+
+using namespace hal;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    initialize
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_initialize
+  (JNIEnv* env, jclass, jint module)
+{
+  int32_t status = 0;
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
+  auto handle = HAL_InitializeREVPH(module, stack.c_str(), &status);
+  CheckStatusForceThrow(env, status);
+  return handle;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    free
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_free
+  (JNIEnv* env, jclass, jint handle)
+{
+  HAL_FreeREVPH(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    checkSolenoidChannel
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_checkSolenoidChannel
+  (JNIEnv*, jclass, jint channel)
+{
+  return HAL_CheckREVPHSolenoidChannel(channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    getCompressor
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_getCompressor
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetREVPHCompressor(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    setClosedLoopControl
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_setClosedLoopControl
+  (JNIEnv* env, jclass, jint handle, jboolean enabled)
+{
+  int32_t status = 0;
+  HAL_SetREVPHClosedLoopControl(handle, enabled, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    getClosedLoopControl
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_getClosedLoopControl
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetREVPHClosedLoopControl(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    getPressureSwitch
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_getPressureSwitch
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetREVPHPressureSwitch(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    getAnalogPressure
+ * Signature: (II)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_getAnalogPressure
+  (JNIEnv* env, jclass, jint handle, jint channel)
+{
+  int32_t status = 0;
+  auto result = HAL_GetREVPHAnalogPressure(handle, channel, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    getCompressorCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_getCompressorCurrent
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetREVPHCompressorCurrent(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    getSolenoids
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_getSolenoids
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t status = 0;
+  auto result = HAL_GetREVPHSolenoids(handle, &status);
+  CheckStatus(env, status, false);
+  return result;
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    setSolenoids
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_setSolenoids
+  (JNIEnv* env, jclass, jint handle, jint mask, jint value)
+{
+  int32_t status = 0;
+  HAL_SetREVPHSolenoids(handle, mask, value, &status);
+  CheckStatus(env, status, false);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_REVPHJNI
+ * Method:    fireOneShot
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_REVPHJNI_fireOneShot
+  (JNIEnv* env, jclass, jint handle, jint index, jint durMs)
+{
+  int32_t status = 0;
+  HAL_FireREVPHOneShot(handle, index, durMs, &status);
+  CheckStatus(env, status, false);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/RelayJNI.cpp b/hal/src/main/native/cpp/jni/RelayJNI.cpp
index ce43307..9e31a9d 100644
--- a/hal/src/main/native/cpp/jni/RelayJNI.cpp
+++ b/hal/src/main/native/cpp/jni/RelayJNI.cpp
@@ -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.
 
 #include <jni.h>
 
 #include <cassert>
 
+#include <wpi/jni_util.h>
+
 #include "HALUtil.h"
 #include "edu_wpi_first_hal_RelayJNI.h"
 #include "hal/Ports.h"
@@ -29,10 +28,10 @@
   (JNIEnv* env, jclass, jint id, jboolean fwd)
 {
   int32_t status = 0;
+  auto stack = wpi::java::GetJavaStackTrace(env, "edu.wpi.first");
   HAL_RelayHandle handle = HAL_InitializeRelayPort(
-      (HAL_PortHandle)id, static_cast<uint8_t>(fwd), &status);
-  CheckStatusRange(env, status, 0, HAL_GetNumRelayChannels(),
-                   hal::getPortHandleChannel((HAL_PortHandle)id));
+      (HAL_PortHandle)id, static_cast<uint8_t>(fwd), stack.c_str(), &status);
+  CheckStatusForceThrow(env, status);
   return (jint)handle;
 }
 
diff --git a/hal/src/main/native/cpp/jni/SPIJNI.cpp b/hal/src/main/native/cpp/jni/SPIJNI.cpp
index d7709e2..67ef56d 100644
--- a/hal/src/main/native/cpp/jni/SPIJNI.cpp
+++ b/hal/src/main/native/cpp/jni/SPIJNI.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 <jni.h>
 
@@ -45,7 +42,7 @@
    jbyte size)
 {
   uint8_t* dataToSendPtr = nullptr;
-  if (dataToSend != 0) {
+  if (dataToSend != nullptr) {
     dataToSendPtr =
         reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataToSend));
   }
@@ -88,7 +85,7 @@
   (JNIEnv* env, jclass, jint port, jobject dataToSend, jbyte size)
 {
   uint8_t* dataToSendPtr = nullptr;
-  if (dataToSend != 0) {
+  if (dataToSend != nullptr) {
     dataToSendPtr =
         reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(dataToSend));
   }
@@ -370,7 +367,9 @@
   jint retval =
       HAL_ReadSPIAutoReceivedData(static_cast<HAL_SPIPort>(port),
                                   recvBuf.data(), numToRead, timeout, &status);
-  if (!CheckStatus(env, status)) return retval;
+  if (!CheckStatus(env, status)) {
+    return retval;
+  }
   if (numToRead > 0) {
     env->SetIntArrayRegion(buffer, 0, numToRead,
                            reinterpret_cast<const jint*>(recvBuf.data()));
diff --git a/hal/src/main/native/cpp/jni/SerialPortJNI.cpp b/hal/src/main/native/cpp/jni/SerialPortJNI.cpp
index 13f1f99..e7f81aa 100644
--- a/hal/src/main/native/cpp/jni/SerialPortJNI.cpp
+++ b/hal/src/main/native/cpp/jni/SerialPortJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp b/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp
index b69a8bb..f681e71 100644
--- a/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp
+++ b/hal/src/main/native/cpp/jni/SimDeviceJNI.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 <jni.h>
 
@@ -69,25 +66,25 @@
 /*
  * Class:     edu_wpi_first_hal_SimDeviceJNI
  * Method:    createSimValueNative
- * Signature: (ILjava/lang/String;ZIJD)I
+ * Signature: (ILjava/lang/String;IIJD)I
  */
 JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueNative
-  (JNIEnv* env, jclass, jint device, jstring name, jboolean readonly, jint type,
+  (JNIEnv* env, jclass, jint device, jstring name, jint direction, jint type,
    jlong value1, jdouble value2)
 {
-  return HAL_CreateSimValue(device, JStringRef{env, name}.c_str(), readonly,
+  return HAL_CreateSimValue(device, JStringRef{env, name}.c_str(), direction,
                             ValueFromJava(type, value1, value2));
 }
 
 /*
  * Class:     edu_wpi_first_hal_SimDeviceJNI
  * Method:    createSimValueEnum
- * Signature: (ILjava/lang/String;Z[Ljava/lang/Object;I)I
+ * Signature: (ILjava/lang/String;I[Ljava/lang/Object;I)I
  */
 JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueEnum
-  (JNIEnv* env, jclass, jint device, jstring name, jboolean readonly,
+  (JNIEnv* env, jclass, jint device, jstring name, jint direction,
    jobjectArray options, jint initialValue)
 {
   size_t len = env->GetArrayLength(options);
@@ -96,13 +93,52 @@
   for (size_t i = 0; i < len; ++i) {
     JLocal<jstring> elem{
         env, static_cast<jstring>(env->GetObjectArrayElement(options, i))};
-    if (!elem) return 0;
-    arr.push_back(JStringRef{env, elem}.str());
+    if (!elem) {
+      return 0;
+    }
+    arr.emplace_back(JStringRef{env, elem}.str());
   }
   wpi::SmallVector<const char*, 8> carr;
-  for (auto&& val : arr) carr.push_back(val.c_str());
-  return HAL_CreateSimValueEnum(device, JStringRef{env, name}.c_str(), readonly,
-                                len, carr.data(), initialValue);
+  for (auto&& val : arr) {
+    carr.push_back(val.c_str());
+  }
+  return HAL_CreateSimValueEnum(device, JStringRef{env, name}.c_str(),
+                                direction, len, carr.data(), initialValue);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    createSimValueEnumDouble
+ * Signature: (ILjava/lang/String;I[Ljava/lang/Object;[DI)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_createSimValueEnumDouble
+  (JNIEnv* env, jclass, jint device, jstring name, jint direction,
+   jobjectArray options, jdoubleArray optionValues, jint initialValue)
+{
+  size_t len = env->GetArrayLength(options);
+  size_t len2 = env->GetArrayLength(optionValues);
+  if (len != len2) {
+    return 0;
+  }
+  std::vector<std::string> arr;
+  arr.reserve(len);
+  for (size_t i = 0; i < len; ++i) {
+    JLocal<jstring> elem{
+        env, static_cast<jstring>(env->GetObjectArrayElement(options, i))};
+    if (!elem) {
+      return 0;
+    }
+    arr.emplace_back(JStringRef{env, elem}.str());
+  }
+
+  wpi::SmallVector<const char*, 8> carr;
+  for (auto&& val : arr) {
+    carr.push_back(val.c_str());
+  }
+  return HAL_CreateSimValueEnumDouble(
+      device, JStringRef{env, name}.c_str(), direction, len, carr.data(),
+      JDoubleArrayRef{env, optionValues}.array().data(), initialValue);
 }
 
 /*
@@ -119,6 +155,30 @@
 
 /*
  * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    getSimValueInt
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_getSimValueInt
+  (JNIEnv*, jclass, jint handle)
+{
+  return HAL_GetSimValueInt(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    getSimValueLong
+ * Signature: (I)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_getSimValueLong
+  (JNIEnv*, jclass, jint handle)
+{
+  return HAL_GetSimValueLong(handle);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
  * Method:    getSimValueDouble
  * Signature: (I)D
  */
@@ -165,4 +225,16 @@
   HAL_SetSimValue(handle, ValueFromJava(type, value1, value2));
 }
 
+/*
+ * Class:     edu_wpi_first_hal_SimDeviceJNI
+ * Method:    resetSimValue
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_SimDeviceJNI_resetSimValue
+  (JNIEnv*, jclass, jint handle)
+{
+  HAL_ResetSimValue(handle);
+}
+
 }  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/SolenoidJNI.cpp b/hal/src/main/native/cpp/jni/SolenoidJNI.cpp
deleted file mode 100644
index 4877db3..0000000
--- a/hal/src/main/native/cpp/jni/SolenoidJNI.cpp
+++ /dev/null
@@ -1,203 +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 <jni.h>
-
-#include "HALUtil.h"
-#include "edu_wpi_first_hal_SolenoidJNI.h"
-#include "hal/Ports.h"
-#include "hal/Solenoid.h"
-#include "hal/handles/HandlesInternal.h"
-
-using namespace hal;
-
-extern "C" {
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    initializeSolenoidPort
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_initializeSolenoidPort
-  (JNIEnv* env, jclass, jint id)
-{
-  int32_t status = 0;
-  HAL_SolenoidHandle handle =
-      HAL_InitializeSolenoidPort((HAL_PortHandle)id, &status);
-
-  // Use solenoid channels, as we have to pick one.
-  CheckStatusRange(env, status, 0, HAL_GetNumSolenoidChannels(),
-                   hal::getPortHandleChannel((HAL_PortHandle)id));
-  return (jint)handle;
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    checkSolenoidChannel
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_checkSolenoidChannel
-  (JNIEnv* env, jclass, jint channel)
-{
-  return HAL_CheckSolenoidChannel(channel);
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    checkSolenoidModule
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_checkSolenoidModule
-  (JNIEnv* env, jclass, jint module)
-{
-  return HAL_CheckSolenoidModule(module);
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    freeSolenoidPort
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_freeSolenoidPort
-  (JNIEnv* env, jclass, jint id)
-{
-  HAL_FreeSolenoidPort((HAL_SolenoidHandle)id);
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    setSolenoid
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_setSolenoid
-  (JNIEnv* env, jclass, jint solenoid_port, jboolean value)
-{
-  int32_t status = 0;
-  HAL_SetSolenoid((HAL_SolenoidHandle)solenoid_port, value, &status);
-  CheckStatus(env, status);
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    getSolenoid
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_getSolenoid
-  (JNIEnv* env, jclass, jint solenoid_port)
-{
-  int32_t status = 0;
-  jboolean val = HAL_GetSolenoid((HAL_SolenoidHandle)solenoid_port, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    getAllSolenoids
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_getAllSolenoids
-  (JNIEnv* env, jclass, jint module)
-{
-  int32_t status = 0;
-  jint val = HAL_GetAllSolenoids(module, &status);
-  CheckStatus(env, status);
-  return val;
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    getPCMSolenoidBlackList
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_getPCMSolenoidBlackList
-  (JNIEnv* env, jclass, jint module)
-{
-  int32_t status = 0;
-  jint val = HAL_GetPCMSolenoidBlackList(module, &status);
-  CheckStatus(env, status);
-  return val;
-}
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    getPCMSolenoidVoltageStickyFault
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_getPCMSolenoidVoltageStickyFault
-  (JNIEnv* env, jclass, jint module)
-{
-  int32_t status = 0;
-  bool val = HAL_GetPCMSolenoidVoltageStickyFault(module, &status);
-  CheckStatus(env, status);
-  return val;
-}
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    getPCMSolenoidVoltageFault
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_getPCMSolenoidVoltageFault
-  (JNIEnv* env, jclass, jint module)
-{
-  int32_t status = 0;
-  bool val = HAL_GetPCMSolenoidVoltageFault(module, &status);
-  CheckStatus(env, status);
-  return val;
-}
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    clearAllPCMStickyFaults
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_clearAllPCMStickyFaults
-  (JNIEnv* env, jclass, jint module)
-{
-  int32_t status = 0;
-  HAL_ClearAllPCMStickyFaults(module, &status);
-  CheckStatus(env, status);
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    setOneShotDuration
- * Signature: (IJ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_setOneShotDuration
-  (JNIEnv* env, jclass, jint solenoid_port, jlong durationMS)
-{
-  int32_t status = 0;
-  HAL_SetOneShotDuration((HAL_SolenoidHandle)solenoid_port, durationMS,
-                         &status);
-  CheckStatus(env, status);
-}
-
-/*
- * Class:     edu_wpi_first_hal_SolenoidJNI
- * Method:    fireOneShot
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_SolenoidJNI_fireOneShot
-  (JNIEnv* env, jclass, jint solenoid_port)
-{
-  int32_t status = 0;
-  HAL_FireOneShot((HAL_SolenoidHandle)solenoid_port, &status);
-  CheckStatus(env, status);
-}
-}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/ThreadsJNI.cpp b/hal/src/main/native/cpp/jni/ThreadsJNI.cpp
index a26a4bf..94f00c5 100644
--- a/hal/src/main/native/cpp/jni/ThreadsJNI.cpp
+++ b/hal/src/main/native/cpp/jni/ThreadsJNI.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 <jni.h>
 
@@ -29,7 +26,7 @@
   HAL_Bool isRT = false;
   auto ret = HAL_GetCurrentThreadPriority(&isRT, &status);
   CheckStatus(env, status);
-  return (jint)ret;
+  return static_cast<jint>(ret);
 }
 
 /*
@@ -45,7 +42,7 @@
   HAL_Bool isRT = false;
   HAL_GetCurrentThreadPriority(&isRT, &status);
   CheckStatus(env, status);
-  return (jboolean)isRT;
+  return static_cast<jboolean>(isRT);
 }
 
 /*
@@ -59,9 +56,9 @@
 {
   int32_t status = 0;
   auto ret = HAL_SetCurrentThreadPriority(
-      (HAL_Bool)realTime, static_cast<int32_t>(priority), &status);
-  CheckStatus(env, status);
-  return (jboolean)ret;
+      static_cast<HAL_Bool>(realTime), static_cast<int32_t>(priority), &status);
+  CheckStatus(env, status, false);
+  return static_cast<jboolean>(ret);
 }
 
 }  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/simulation/AccelerometerDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/AccelerometerDataJNI.cpp
index 21d93fe..bc0b499 100644
--- a/hal/src/main/native/cpp/jni/simulation/AccelerometerDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/AccelerometerDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp
index 8ac59ec..e888bd3 100644
--- a/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.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 <jni.h>
 
@@ -260,7 +257,7 @@
       std::make_unique<HAL_AddressableLEDData[]>(HAL_kAddressableLEDMaxLength);
   int32_t length = HALSIM_GetAddressableLEDData(index, data.get());
   return MakeJByteArray(
-      env, wpi::ArrayRef(reinterpret_cast<jbyte*>(data.get()), length * 4));
+      env, wpi::span(reinterpret_cast<jbyte*>(data.get()), length * 4));
 }
 
 /*
diff --git a/hal/src/main/native/cpp/jni/simulation/AnalogGyroDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/AnalogGyroDataJNI.cpp
index ed867cd..6a916f5 100644
--- a/hal/src/main/native/cpp/jni/simulation/AnalogGyroDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/AnalogGyroDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/AnalogInDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/AnalogInDataJNI.cpp
index 0266a76..336c0f4 100644
--- a/hal/src/main/native/cpp/jni/simulation/AnalogInDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/AnalogInDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/AnalogOutDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/AnalogOutDataJNI.cpp
index 06f5be6..ce74fad 100644
--- a/hal/src/main/native/cpp/jni/simulation/AnalogOutDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/AnalogOutDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/AnalogTriggerDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/AnalogTriggerDataJNI.cpp
index be92c6d..f7a5147 100644
--- a/hal/src/main/native/cpp/jni/simulation/AnalogTriggerDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/AnalogTriggerDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.cpp b/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.cpp
index 6751e03..265b363 100644
--- a/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.cpp
@@ -1,14 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "BufferCallbackStore.h"
 
 #include <jni.h>
 
+#include <cstdio>
+
 #include <wpi/jni_util.h>
 
 #include "SimulatorJNI.h"
@@ -25,16 +24,14 @@
                                     hal::HAL_HandleEnum::SimulationJni>*
     callbackHandles;
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 void InitializeBufferStore() {
   static hal::UnlimitedHandleResource<SIM_JniHandle, BufferCallbackStore,
                                       hal::HAL_HandleEnum::SimulationJni>
       cb;
   callbackHandles = &cb;
 }
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
 
 void BufferCallbackStore::create(JNIEnv* env, jobject obj) {
   m_call = JGlobal<jobject>(env, obj);
@@ -51,21 +48,21 @@
     didAttachThread = true;
     if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
       // Failed to attach, log and return
-      wpi::outs() << "Failed to attach\n";
-      wpi::outs().flush();
+      std::puts("Failed to attach");
+      std::fflush(stdout);
       return;
     }
   } else if (tryGetEnv == JNI_EVERSION) {
-    wpi::outs() << "Invalid JVM Version requested\n";
-    wpi::outs().flush();
+    std::puts("Invalid JVM Version requested");
+    std::fflush(stdout);
   }
 
-  auto toCallbackArr =
-      MakeJByteArray(env, wpi::StringRef{reinterpret_cast<const char*>(buffer),
-                                         static_cast<size_t>(length)});
+  auto toCallbackArr = MakeJByteArray(
+      env, std::string_view{reinterpret_cast<const char*>(buffer),
+                            static_cast<size_t>(length)});
 
   env->CallVoidMethod(m_call, sim::GetBufferCallback(), MakeJString(env, name),
-                      toCallbackArr, (jint)length);
+                      toCallbackArr, static_cast<jint>(length));
 
   jbyte* fromCallbackArr = reinterpret_cast<jbyte*>(
       env->GetPrimitiveArrayCritical(toCallbackArr, nullptr));
@@ -85,7 +82,9 @@
   }
 }
 
-void BufferCallbackStore::free(JNIEnv* env) { m_call.free(env); }
+void BufferCallbackStore::free(JNIEnv* env) {
+  m_call.free(env);
+}
 
 SIM_JniHandle sim::AllocateBufferCallback(
     JNIEnv* env, jint index, jobject callback,
@@ -108,7 +107,9 @@
     uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
     SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
     auto data = callbackHandles->Get(handle);
-    if (!data) return;
+    if (!data) {
+      return;
+    }
 
     data->performCallback(name, buffer, length);
   };
diff --git a/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.h b/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.h
index 8e746d2..73cf957 100644
--- a/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.h
+++ b/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -17,8 +14,7 @@
 #include "hal/handles/UnlimitedHandleResource.h"
 #include "hal/simulation/NotifyListener.h"
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 class BufferCallbackStore {
  public:
   void create(JNIEnv* env, jobject obj);
@@ -34,14 +30,13 @@
 
 void InitializeBufferStore();
 
-typedef int32_t (*RegisterBufferCallbackFunc)(int32_t index,
-                                              HAL_BufferCallback callback,
-                                              void* param);
-typedef void (*FreeBufferCallbackFunc)(int32_t index, int32_t uid);
+using RegisterBufferCallbackFunc = int32_t (*)(int32_t index,
+                                               HAL_BufferCallback callback,
+                                               void* param);
+using FreeBufferCallbackFunc = void (*)(int32_t index, int32_t uid);
 
 SIM_JniHandle AllocateBufferCallback(JNIEnv* env, jint index, jobject callback,
                                      RegisterBufferCallbackFunc createCallback);
 void FreeBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
                         FreeBufferCallbackFunc freeCallback);
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
diff --git a/hal/src/main/native/cpp/jni/simulation/CTREPCMDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/CTREPCMDataJNI.cpp
new file mode 100644
index 0000000..416478c
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/simulation/CTREPCMDataJNI.cpp
@@ -0,0 +1,368 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_simulation_CTREPCMDataJNI.h"
+#include "hal/simulation/CTREPCMData.h"
+
+using namespace hal;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterCTREPCMInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelCTREPCMInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetCTREPCMInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetCTREPCMInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    registerSolenoidOutputCallback
+ * Signature: (IILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_registerSolenoidOutputCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  return sim::AllocateChannelCallback(
+      env, index, channel, callback, initialNotify,
+      &HALSIM_RegisterCTREPCMSolenoidOutputCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    cancelSolenoidOutputCallback
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_cancelSolenoidOutputCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
+{
+  return sim::FreeChannelCallback(env, handle, index, channel,
+                                  &HALSIM_CancelCTREPCMSolenoidOutputCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    getSolenoidOutput
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_getSolenoidOutput
+  (JNIEnv*, jclass, jint index, jint channel)
+{
+  return HALSIM_GetCTREPCMSolenoidOutput(index, channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    setSolenoidOutput
+ * Signature: (IIZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_setSolenoidOutput
+  (JNIEnv*, jclass, jint index, jint channel, jboolean value)
+{
+  HALSIM_SetCTREPCMSolenoidOutput(index, channel, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    registerCompressorOnCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_registerCompressorOnCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterCTREPCMCompressorOnCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    cancelCompressorOnCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_cancelCompressorOnCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelCTREPCMCompressorOnCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    getCompressorOn
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_getCompressorOn
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetCTREPCMCompressorOn(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    setCompressorOn
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_setCompressorOn
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetCTREPCMCompressorOn(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    registerClosedLoopEnabledCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_registerClosedLoopEnabledCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterCTREPCMClosedLoopEnabledCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    cancelClosedLoopEnabledCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_cancelClosedLoopEnabledCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelCTREPCMClosedLoopEnabledCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    getClosedLoopEnabled
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_getClosedLoopEnabled
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetCTREPCMClosedLoopEnabled(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    setClosedLoopEnabled
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_setClosedLoopEnabled
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetCTREPCMClosedLoopEnabled(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    registerPressureSwitchCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_registerPressureSwitchCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterCTREPCMPressureSwitchCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    cancelPressureSwitchCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_cancelPressureSwitchCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelCTREPCMPressureSwitchCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    getPressureSwitch
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_getPressureSwitch
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetCTREPCMPressureSwitch(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    setPressureSwitch
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_setPressureSwitch
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetCTREPCMPressureSwitch(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    registerCompressorCurrentCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_registerCompressorCurrentCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterCTREPCMCompressorCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    cancelCompressorCurrentCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_cancelCompressorCurrentCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelCTREPCMCompressorCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    getCompressorCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_getCompressorCurrent
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetCTREPCMCompressorCurrent(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    setCompressorCurrent
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_setCompressorCurrent
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetCTREPCMCompressorCurrent(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    registerAllNonSolenoidCallbacks
+ * Signature: (ILjava/lang/Object;Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_registerAllNonSolenoidCallbacks
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      [](int32_t index, HAL_NotifyCallback cb, void* param, HAL_Bool in) {
+        HALSIM_RegisterCTREPCMAllNonSolenoidCallbacks(index, cb, param, in);
+        return 0;
+      });
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    registerAllSolenoidCallbacks
+ * Signature: (IILjava/lang/Object;Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_registerAllSolenoidCallbacks
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  sim::AllocateChannelCallback(
+      env, index, channel, callback, initialNotify,
+      [](int32_t index, int32_t channel, HAL_NotifyCallback cb, void* param,
+         HAL_Bool in) {
+        HALSIM_RegisterCTREPCMAllSolenoidCallbacks(index, channel, cb, param,
+                                                   in);
+        return 0;
+      });
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_CTREPCMDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_CTREPCMDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetCTREPCMData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/simulation/CallbackStore.cpp b/hal/src/main/native/cpp/jni/simulation/CallbackStore.cpp
index 5ce046d..f57dfb3 100644
--- a/hal/src/main/native/cpp/jni/simulation/CallbackStore.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/CallbackStore.cpp
@@ -1,14 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "CallbackStore.h"
 
 #include <jni.h>
 
+#include <cstdio>
+
 #include <wpi/jni_util.h>
 
 #include "SimulatorJNI.h"
@@ -25,16 +24,14 @@
                                     hal::HAL_HandleEnum::SimulationJni>*
     callbackHandles;
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 void InitializeStore() {
   static hal::UnlimitedHandleResource<SIM_JniHandle, CallbackStore,
                                       hal::HAL_HandleEnum::SimulationJni>
       cb;
   callbackHandles = &cb;
 }
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
 
 void CallbackStore::create(JNIEnv* env, jobject obj) {
   m_call = JGlobal<jobject>(env, obj);
@@ -50,18 +47,39 @@
     didAttachThread = true;
     if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
       // Failed to attach, log and return
-      wpi::outs() << "Failed to attach\n";
-      wpi::outs().flush();
+      std::puts("Failed to attach");
+      std::fflush(stdout);
       return;
     }
   } else if (tryGetEnv == JNI_EVERSION) {
-    wpi::outs() << "Invalid JVM Version requested\n";
-    wpi::outs().flush();
+    std::puts("Invalid JVM Version requested");
+    std::fflush(stdout);
+  }
+
+  int64_t longValue = 0;
+
+  switch (value->type) {
+    case HAL_BOOLEAN:
+      longValue = value->data.v_boolean;
+      break;
+    case HAL_ENUM:
+      longValue = value->data.v_enum;
+      break;
+    case HAL_INT:
+      longValue = value->data.v_int;
+      break;
+    case HAL_LONG:
+      longValue = value->data.v_long;
+      break;
+    case HAL_DOUBLE:
+    case HAL_UNASSIGNED:
+      break;
   }
 
   env->CallVoidMethod(m_call, sim::GetNotifyCallback(), MakeJString(env, name),
-                      (jint)value->type, (jlong)value->data.v_long,
-                      (jdouble)value->data.v_double);
+                      static_cast<jint>(value->type),
+                      static_cast<jlong>(longValue),
+                      static_cast<jdouble>(value->data.v_double));
 
   if (env->ExceptionCheck()) {
     env->ExceptionDescribe();
@@ -72,7 +90,9 @@
   }
 }
 
-void CallbackStore::free(JNIEnv* env) { m_call.free(env); }
+void CallbackStore::free(JNIEnv* env) {
+  m_call.free(env);
+}
 
 SIM_JniHandle sim::AllocateCallback(JNIEnv* env, jint index, jobject callback,
                                     jboolean initialNotify,
@@ -95,7 +115,9 @@
     uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
     SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
     auto data = callbackHandles->Get(handle);
-    if (!data) return;
+    if (!data) {
+      return;
+    }
 
     data->performCallback(name, value);
   };
@@ -135,7 +157,9 @@
     uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
     SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
     auto data = callbackHandles->Get(handle);
-    if (!data) return;
+    if (!data) {
+      return;
+    }
 
     data->performCallback(name, value);
   };
@@ -177,7 +201,9 @@
     uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
     SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
     auto data = callbackHandles->Get(handle);
-    if (!data) return;
+    if (!data) {
+      return;
+    }
 
     data->performCallback(name, value);
   };
diff --git a/hal/src/main/native/cpp/jni/simulation/CallbackStore.h b/hal/src/main/native/cpp/jni/simulation/CallbackStore.h
index 0ba44d3..59e1018 100644
--- a/hal/src/main/native/cpp/jni/simulation/CallbackStore.h
+++ b/hal/src/main/native/cpp/jni/simulation/CallbackStore.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -17,8 +14,7 @@
 #include "hal/handles/UnlimitedHandleResource.h"
 #include "hal/simulation/NotifyListener.h"
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 class CallbackStore {
  public:
   void create(JNIEnv* env, jobject obj);
@@ -34,20 +30,20 @@
 
 void InitializeStore();
 
-typedef int32_t (*RegisterCallbackFunc)(int32_t index,
-                                        HAL_NotifyCallback callback,
-                                        void* param, HAL_Bool initialNotify);
-typedef void (*FreeCallbackFunc)(int32_t index, int32_t uid);
-typedef int32_t (*RegisterChannelCallbackFunc)(int32_t index, int32_t channel,
-                                               HAL_NotifyCallback callback,
-                                               void* param,
-                                               HAL_Bool initialNotify);
-typedef void (*FreeChannelCallbackFunc)(int32_t index, int32_t channel,
-                                        int32_t uid);
-typedef int32_t (*RegisterCallbackNoIndexFunc)(HAL_NotifyCallback callback,
-                                               void* param,
-                                               HAL_Bool initialNotify);
-typedef void (*FreeCallbackNoIndexFunc)(int32_t uid);
+using RegisterCallbackFunc = int32_t (*)(int32_t index,
+                                         HAL_NotifyCallback callback,
+                                         void* param, HAL_Bool initialNotify);
+using FreeCallbackFunc = void (*)(int32_t index, int32_t uid);
+using RegisterChannelCallbackFunc = int32_t (*)(int32_t index, int32_t channel,
+                                                HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify);
+using FreeChannelCallbackFunc = void (*)(int32_t index, int32_t channel,
+                                         int32_t uid);
+using RegisterCallbackNoIndexFunc = int32_t (*)(HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify);
+using FreeCallbackNoIndexFunc = void (*)(int32_t uid);
 
 SIM_JniHandle AllocateCallback(JNIEnv* env, jint index, jobject callback,
                                jboolean initialNotify,
@@ -64,5 +60,4 @@
                          jint channel, FreeChannelCallbackFunc freeCallback);
 void FreeCallbackNoIndex(JNIEnv* env, SIM_JniHandle handle,
                          FreeCallbackNoIndexFunc freeCallback);
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
diff --git a/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.cpp b/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.cpp
index b9c9808..cba0a5b 100644
--- a/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.cpp
@@ -1,14 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "ConstBufferCallbackStore.h"
 
 #include <jni.h>
 
+#include <cstdio>
+
 #include <wpi/jni_util.h>
 
 #include "SimulatorJNI.h"
@@ -25,16 +24,14 @@
                                     hal::HAL_HandleEnum::SimulationJni>*
     callbackHandles;
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 void InitializeConstBufferStore() {
   static hal::UnlimitedHandleResource<SIM_JniHandle, ConstBufferCallbackStore,
                                       hal::HAL_HandleEnum::SimulationJni>
       cb;
   callbackHandles = &cb;
 }
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
 
 void ConstBufferCallbackStore::create(JNIEnv* env, jobject obj) {
   m_call = JGlobal<jobject>(env, obj);
@@ -52,21 +49,22 @@
     didAttachThread = true;
     if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
       // Failed to attach, log and return
-      wpi::outs() << "Failed to attach\n";
-      wpi::outs().flush();
+      std::puts("Failed to attach");
+      std::fflush(stdout);
       return;
     }
   } else if (tryGetEnv == JNI_EVERSION) {
-    wpi::outs() << "Invalid JVM Version requested\n";
-    wpi::outs().flush();
+    std::puts("Invalid JVM Version requested");
+    std::fflush(stdout);
   }
 
-  auto toCallbackArr =
-      MakeJByteArray(env, wpi::StringRef{reinterpret_cast<const char*>(buffer),
-                                         static_cast<size_t>(length)});
+  auto toCallbackArr = MakeJByteArray(
+      env, std::string_view{reinterpret_cast<const char*>(buffer),
+                            static_cast<size_t>(length)});
 
   env->CallVoidMethod(m_call, sim::GetConstBufferCallback(),
-                      MakeJString(env, name), toCallbackArr, (jint)length);
+                      MakeJString(env, name), toCallbackArr,
+                      static_cast<jint>(length));
 
   if (env->ExceptionCheck()) {
     env->ExceptionDescribe();
@@ -77,7 +75,9 @@
   }
 }
 
-void ConstBufferCallbackStore::free(JNIEnv* env) { m_call.free(env); }
+void ConstBufferCallbackStore::free(JNIEnv* env) {
+  m_call.free(env);
+}
 
 SIM_JniHandle sim::AllocateConstBufferCallback(
     JNIEnv* env, jint index, jobject callback,
@@ -100,7 +100,9 @@
     uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
     SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
     auto data = callbackHandles->Get(handle);
-    if (!data) return;
+    if (!data) {
+      return;
+    }
 
     data->performCallback(name, buffer, length);
   };
diff --git a/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.h b/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.h
index b69eccf..0998d3c 100644
--- a/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.h
+++ b/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -17,8 +14,7 @@
 #include "hal/handles/UnlimitedHandleResource.h"
 #include "hal/simulation/NotifyListener.h"
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 class ConstBufferCallbackStore {
  public:
   void create(JNIEnv* env, jobject obj);
@@ -35,14 +31,13 @@
 
 void InitializeConstBufferStore();
 
-typedef int32_t (*RegisterConstBufferCallbackFunc)(
-    int32_t index, HAL_ConstBufferCallback callback, void* param);
-typedef void (*FreeConstBufferCallbackFunc)(int32_t index, int32_t uid);
+using RegisterConstBufferCallbackFunc =
+    int32_t (*)(int32_t index, HAL_ConstBufferCallback callback, void* param);
+using FreeConstBufferCallbackFunc = void (*)(int32_t index, int32_t uid);
 
 SIM_JniHandle AllocateConstBufferCallback(
     JNIEnv* env, jint index, jobject callback,
     RegisterConstBufferCallbackFunc createCallback);
 void FreeConstBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
                              FreeConstBufferCallbackFunc freeCallback);
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
diff --git a/hal/src/main/native/cpp/jni/simulation/DIODataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/DIODataJNI.cpp
index f757558..e81ad77 100644
--- a/hal/src/main/native/cpp/jni/simulation/DIODataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/DIODataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/DigitalPWMDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/DigitalPWMDataJNI.cpp
index ea6bee2..3ba3931 100644
--- a/hal/src/main/native/cpp/jni/simulation/DigitalPWMDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/DigitalPWMDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp
index 7868e43..acecacb 100644
--- a/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/DriverStationDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/DutyCycleDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/DutyCycleDataJNI.cpp
index 054fa67..9cda86d 100644
--- a/hal/src/main/native/cpp/jni/simulation/DutyCycleDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/DutyCycleDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/EncoderDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/EncoderDataJNI.cpp
index b97e0fe..69549a1 100644
--- a/hal/src/main/native/cpp/jni/simulation/EncoderDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/EncoderDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/I2CDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/I2CDataJNI.cpp
index e4c2259..c023754 100644
--- a/hal/src/main/native/cpp/jni/simulation/I2CDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/I2CDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/NotifierDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/NotifierDataJNI.cpp
index 845c164..15b02d7 100644
--- a/hal/src/main/native/cpp/jni/simulation/NotifierDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/NotifierDataJNI.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 "edu_wpi_first_hal_simulation_NotifierDataJNI.h"
 #include "hal/simulation/NotifierData.h"
diff --git a/hal/src/main/native/cpp/jni/simulation/PCMDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/PCMDataJNI.cpp
deleted file mode 100644
index cfcd2c0..0000000
--- a/hal/src/main/native/cpp/jni/simulation/PCMDataJNI.cpp
+++ /dev/null
@@ -1,421 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include <jni.h>
-
-#include "CallbackStore.h"
-#include "edu_wpi_first_hal_simulation_PCMDataJNI.h"
-#include "hal/simulation/PCMData.h"
-
-using namespace hal;
-
-extern "C" {
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerSolenoidInitializedCallback
- * Signature: (IILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerSolenoidInitializedCallback
-  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
-   jboolean initialNotify)
-{
-  return sim::AllocateChannelCallback(
-      env, index, channel, callback, initialNotify,
-      &HALSIM_RegisterPCMSolenoidInitializedCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    cancelSolenoidInitializedCallback
- * Signature: (III)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_cancelSolenoidInitializedCallback
-  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
-{
-  return sim::FreeChannelCallback(env, handle, index, channel,
-                                  &HALSIM_CancelPCMSolenoidInitializedCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    getSolenoidInitialized
- * Signature: (II)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_getSolenoidInitialized
-  (JNIEnv*, jclass, jint index, jint channel)
-{
-  return HALSIM_GetPCMSolenoidInitialized(index, channel);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    setSolenoidInitialized
- * Signature: (IIZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_setSolenoidInitialized
-  (JNIEnv*, jclass, jint index, jint channel, jboolean value)
-{
-  HALSIM_SetPCMSolenoidInitialized(index, channel, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerSolenoidOutputCallback
- * Signature: (IILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerSolenoidOutputCallback
-  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
-   jboolean initialNotify)
-{
-  return sim::AllocateChannelCallback(
-      env, index, channel, callback, initialNotify,
-      &HALSIM_RegisterPCMSolenoidOutputCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    cancelSolenoidOutputCallback
- * Signature: (III)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_cancelSolenoidOutputCallback
-  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
-{
-  return sim::FreeChannelCallback(env, handle, index, channel,
-                                  &HALSIM_CancelPCMSolenoidOutputCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    getSolenoidOutput
- * Signature: (II)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_getSolenoidOutput
-  (JNIEnv*, jclass, jint index, jint channel)
-{
-  return HALSIM_GetPCMSolenoidOutput(index, channel);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    setSolenoidOutput
- * Signature: (IIZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_setSolenoidOutput
-  (JNIEnv*, jclass, jint index, jint channel, jboolean value)
-{
-  HALSIM_SetPCMSolenoidOutput(index, channel, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerCompressorInitializedCallback
- * Signature: (ILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerCompressorInitializedCallback
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  return sim::AllocateCallback(
-      env, index, callback, initialNotify,
-      &HALSIM_RegisterPCMCompressorInitializedCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    cancelCompressorInitializedCallback
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_cancelCompressorInitializedCallback
-  (JNIEnv* env, jclass, jint index, jint handle)
-{
-  return sim::FreeCallback(env, handle, index,
-                           &HALSIM_CancelPCMCompressorInitializedCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    getCompressorInitialized
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_getCompressorInitialized
-  (JNIEnv*, jclass, jint index)
-{
-  return HALSIM_GetPCMCompressorInitialized(index);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    setCompressorInitialized
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_setCompressorInitialized
-  (JNIEnv*, jclass, jint index, jboolean value)
-{
-  HALSIM_SetPCMCompressorInitialized(index, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerCompressorOnCallback
- * Signature: (ILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerCompressorOnCallback
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  return sim::AllocateCallback(env, index, callback, initialNotify,
-                               &HALSIM_RegisterPCMCompressorOnCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    cancelCompressorOnCallback
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_cancelCompressorOnCallback
-  (JNIEnv* env, jclass, jint index, jint handle)
-{
-  return sim::FreeCallback(env, handle, index,
-                           &HALSIM_CancelPCMCompressorOnCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    getCompressorOn
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_getCompressorOn
-  (JNIEnv*, jclass, jint index)
-{
-  return HALSIM_GetPCMCompressorOn(index);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    setCompressorOn
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_setCompressorOn
-  (JNIEnv*, jclass, jint index, jboolean value)
-{
-  HALSIM_SetPCMCompressorOn(index, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerClosedLoopEnabledCallback
- * Signature: (ILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerClosedLoopEnabledCallback
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  return sim::AllocateCallback(env, index, callback, initialNotify,
-                               &HALSIM_RegisterPCMClosedLoopEnabledCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    cancelClosedLoopEnabledCallback
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_cancelClosedLoopEnabledCallback
-  (JNIEnv* env, jclass, jint index, jint handle)
-{
-  return sim::FreeCallback(env, handle, index,
-                           &HALSIM_CancelPCMClosedLoopEnabledCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    getClosedLoopEnabled
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_getClosedLoopEnabled
-  (JNIEnv*, jclass, jint index)
-{
-  return HALSIM_GetPCMClosedLoopEnabled(index);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    setClosedLoopEnabled
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_setClosedLoopEnabled
-  (JNIEnv*, jclass, jint index, jboolean value)
-{
-  HALSIM_SetPCMClosedLoopEnabled(index, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerPressureSwitchCallback
- * Signature: (ILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerPressureSwitchCallback
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  return sim::AllocateCallback(env, index, callback, initialNotify,
-                               &HALSIM_RegisterPCMPressureSwitchCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    cancelPressureSwitchCallback
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_cancelPressureSwitchCallback
-  (JNIEnv* env, jclass, jint index, jint handle)
-{
-  return sim::FreeCallback(env, handle, index,
-                           &HALSIM_CancelPCMPressureSwitchCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    getPressureSwitch
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_getPressureSwitch
-  (JNIEnv*, jclass, jint index)
-{
-  return HALSIM_GetPCMPressureSwitch(index);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    setPressureSwitch
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_setPressureSwitch
-  (JNIEnv*, jclass, jint index, jboolean value)
-{
-  HALSIM_SetPCMPressureSwitch(index, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerCompressorCurrentCallback
- * Signature: (ILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerCompressorCurrentCallback
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  return sim::AllocateCallback(env, index, callback, initialNotify,
-                               &HALSIM_RegisterPCMCompressorCurrentCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    cancelCompressorCurrentCallback
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_cancelCompressorCurrentCallback
-  (JNIEnv* env, jclass, jint index, jint handle)
-{
-  return sim::FreeCallback(env, handle, index,
-                           &HALSIM_CancelPCMCompressorCurrentCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    getCompressorCurrent
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_getCompressorCurrent
-  (JNIEnv*, jclass, jint index)
-{
-  return HALSIM_GetPCMCompressorCurrent(index);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    setCompressorCurrent
- * Signature: (ID)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_setCompressorCurrent
-  (JNIEnv*, jclass, jint index, jdouble value)
-{
-  HALSIM_SetPCMCompressorCurrent(index, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerAllNonSolenoidCallbacks
- * Signature: (ILjava/lang/Object;Z)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerAllNonSolenoidCallbacks
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  sim::AllocateCallback(
-      env, index, callback, initialNotify,
-      [](int32_t index, HAL_NotifyCallback cb, void* param, HAL_Bool in) {
-        HALSIM_RegisterPCMAllNonSolenoidCallbacks(index, cb, param, in);
-        return 0;
-      });
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    registerAllSolenoidCallbacks
- * Signature: (IILjava/lang/Object;Z)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_registerAllSolenoidCallbacks
-  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
-   jboolean initialNotify)
-{
-  sim::AllocateChannelCallback(
-      env, index, channel, callback, initialNotify,
-      [](int32_t index, int32_t channel, HAL_NotifyCallback cb, void* param,
-         HAL_Bool in) {
-        HALSIM_RegisterPCMAllSolenoidCallbacks(index, channel, cb, param, in);
-        return 0;
-      });
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PCMDataJNI
- * Method:    resetData
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PCMDataJNI_resetData
-  (JNIEnv*, jclass, jint index)
-{
-  HALSIM_ResetPCMData(index);
-}
-
-}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/simulation/PDPDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/PDPDataJNI.cpp
deleted file mode 100644
index 2ce6cbd..0000000
--- a/hal/src/main/native/cpp/jni/simulation/PDPDataJNI.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include <jni.h>
-
-#include "CallbackStore.h"
-#include "edu_wpi_first_hal_simulation_PDPDataJNI.h"
-#include "hal/simulation/PDPData.h"
-
-using namespace hal;
-
-extern "C" {
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    registerInitializedCallback
- * Signature: (ILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_registerInitializedCallback
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  return sim::AllocateCallback(env, index, callback, initialNotify,
-                               &HALSIM_RegisterPDPInitializedCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    cancelInitializedCallback
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_cancelInitializedCallback
-  (JNIEnv* env, jclass, jint index, jint handle)
-{
-  return sim::FreeCallback(env, handle, index,
-                           &HALSIM_CancelPDPInitializedCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    getInitialized
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_getInitialized
-  (JNIEnv*, jclass, jint index)
-{
-  return HALSIM_GetPDPInitialized(index);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    setInitialized
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_setInitialized
-  (JNIEnv*, jclass, jint index, jboolean value)
-{
-  HALSIM_SetPDPInitialized(index, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    registerTemperatureCallback
- * Signature: (ILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_registerTemperatureCallback
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  return sim::AllocateCallback(env, index, callback, initialNotify,
-                               &HALSIM_RegisterPDPTemperatureCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    cancelTemperatureCallback
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_cancelTemperatureCallback
-  (JNIEnv* env, jclass, jint index, jint handle)
-{
-  return sim::FreeCallback(env, handle, index,
-                           &HALSIM_CancelPDPTemperatureCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    getTemperature
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_getTemperature
-  (JNIEnv*, jclass, jint index)
-{
-  return HALSIM_GetPDPTemperature(index);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    setTemperature
- * Signature: (ID)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_setTemperature
-  (JNIEnv*, jclass, jint index, jdouble value)
-{
-  HALSIM_SetPDPTemperature(index, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    registerVoltageCallback
- * Signature: (ILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_registerVoltageCallback
-  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
-{
-  return sim::AllocateCallback(env, index, callback, initialNotify,
-                               &HALSIM_RegisterPDPVoltageCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    cancelVoltageCallback
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_cancelVoltageCallback
-  (JNIEnv* env, jclass, jint index, jint handle)
-{
-  return sim::FreeCallback(env, handle, index,
-                           &HALSIM_CancelPDPVoltageCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    getVoltage
- * Signature: (I)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_getVoltage
-  (JNIEnv*, jclass, jint index)
-{
-  return HALSIM_GetPDPVoltage(index);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    setVoltage
- * Signature: (ID)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_setVoltage
-  (JNIEnv*, jclass, jint index, jdouble value)
-{
-  HALSIM_SetPDPVoltage(index, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    registerCurrentCallback
- * Signature: (IILjava/lang/Object;Z)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_registerCurrentCallback
-  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
-   jboolean initialNotify)
-{
-  return sim::AllocateChannelCallback(env, index, channel, callback,
-                                      initialNotify,
-                                      &HALSIM_RegisterPDPCurrentCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    cancelCurrentCallback
- * Signature: (III)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_cancelCurrentCallback
-  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
-{
-  return sim::FreeChannelCallback(env, handle, index, channel,
-                                  &HALSIM_CancelPDPCurrentCallback);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    getCurrent
- * Signature: (II)D
- */
-JNIEXPORT jdouble JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_getCurrent
-  (JNIEnv*, jclass, jint index, jint channel)
-{
-  return HALSIM_GetPDPCurrent(index, channel);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    setCurrent
- * Signature: (IID)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_setCurrent
-  (JNIEnv*, jclass, jint index, jint channel, jdouble value)
-{
-  HALSIM_SetPDPCurrent(index, channel, value);
-}
-
-/*
- * Class:     edu_wpi_first_hal_simulation_PDPDataJNI
- * Method:    resetData
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_hal_simulation_PDPDataJNI_resetData
-  (JNIEnv*, jclass, jint index)
-{
-  HALSIM_ResetPDPData(index);
-}
-
-}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/simulation/PWMDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/PWMDataJNI.cpp
index 03e61ef..31c79a7 100644
--- a/hal/src/main/native/cpp/jni/simulation/PWMDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/PWMDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/PowerDistributionDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/PowerDistributionDataJNI.cpp
new file mode 100644
index 0000000..517dc09
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/simulation/PowerDistributionDataJNI.cpp
@@ -0,0 +1,233 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_simulation_PowerDistributionDataJNI.h"
+#include "hal/simulation/PowerDistributionData.h"
+
+using namespace hal;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterPowerDistributionInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPowerDistributionInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPowerDistributionInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetPowerDistributionInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    registerTemperatureCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_registerTemperatureCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterPowerDistributionTemperatureCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    cancelTemperatureCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_cancelTemperatureCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPowerDistributionTemperatureCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    getTemperature
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_getTemperature
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPowerDistributionTemperature(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    setTemperature
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_setTemperature
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetPowerDistributionTemperature(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    registerVoltageCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_registerVoltageCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      &HALSIM_RegisterPowerDistributionVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    cancelVoltageCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_cancelVoltageCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelPowerDistributionVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    getVoltage
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_getVoltage
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetPowerDistributionVoltage(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    setVoltage
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_setVoltage
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetPowerDistributionVoltage(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    registerCurrentCallback
+ * Signature: (IILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_registerCurrentCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  return sim::AllocateChannelCallback(
+      env, index, channel, callback, initialNotify,
+      &HALSIM_RegisterPowerDistributionCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    cancelCurrentCallback
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_cancelCurrentCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
+{
+  return sim::FreeChannelCallback(
+      env, handle, index, channel,
+      &HALSIM_CancelPowerDistributionCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    getCurrent
+ * Signature: (II)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_getCurrent
+  (JNIEnv*, jclass, jint index, jint channel)
+{
+  return HALSIM_GetPowerDistributionCurrent(index, channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    setCurrent
+ * Signature: (IID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_setCurrent
+  (JNIEnv*, jclass, jint index, jint channel, jdouble value)
+{
+  HALSIM_SetPowerDistributionCurrent(index, channel, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_PowerDistributionDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_PowerDistributionDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetPowerDistributionData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/simulation/REVPHDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/REVPHDataJNI.cpp
new file mode 100644
index 0000000..da473de
--- /dev/null
+++ b/hal/src/main/native/cpp/jni/simulation/REVPHDataJNI.cpp
@@ -0,0 +1,365 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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 <jni.h>
+
+#include "CallbackStore.h"
+#include "edu_wpi_first_hal_simulation_REVPHDataJNI.h"
+#include "hal/simulation/REVPHData.h"
+
+using namespace hal;
+
+extern "C" {
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    registerInitializedCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerInitializedCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterREVPHInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    cancelInitializedCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelInitializedCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelREVPHInitializedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    getInitialized
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getInitialized
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetREVPHInitialized(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    setInitialized
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setInitialized
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetREVPHInitialized(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    registerSolenoidOutputCallback
+ * Signature: (IILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerSolenoidOutputCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  return sim::AllocateChannelCallback(
+      env, index, channel, callback, initialNotify,
+      &HALSIM_RegisterREVPHSolenoidOutputCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    cancelSolenoidOutputCallback
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelSolenoidOutputCallback
+  (JNIEnv* env, jclass, jint index, jint channel, jint handle)
+{
+  return sim::FreeChannelCallback(env, handle, index, channel,
+                                  &HALSIM_CancelREVPHSolenoidOutputCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    getSolenoidOutput
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getSolenoidOutput
+  (JNIEnv*, jclass, jint index, jint channel)
+{
+  return HALSIM_GetREVPHSolenoidOutput(index, channel);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    setSolenoidOutput
+ * Signature: (IIZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setSolenoidOutput
+  (JNIEnv*, jclass, jint index, jint channel, jboolean value)
+{
+  HALSIM_SetREVPHSolenoidOutput(index, channel, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    registerCompressorOnCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerCompressorOnCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterREVPHCompressorOnCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    cancelCompressorOnCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelCompressorOnCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelREVPHCompressorOnCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    getCompressorOn
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getCompressorOn
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetREVPHCompressorOn(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    setCompressorOn
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setCompressorOn
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetREVPHCompressorOn(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    registerClosedLoopEnabledCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerClosedLoopEnabledCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterREVPHClosedLoopEnabledCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    cancelClosedLoopEnabledCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelClosedLoopEnabledCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelREVPHClosedLoopEnabledCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    getClosedLoopEnabled
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getClosedLoopEnabled
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetREVPHClosedLoopEnabled(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    setClosedLoopEnabled
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setClosedLoopEnabled
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetREVPHClosedLoopEnabled(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    registerPressureSwitchCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerPressureSwitchCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterREVPHPressureSwitchCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    cancelPressureSwitchCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelPressureSwitchCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelREVPHPressureSwitchCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    getPressureSwitch
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getPressureSwitch
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetREVPHPressureSwitch(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    setPressureSwitch
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setPressureSwitch
+  (JNIEnv*, jclass, jint index, jboolean value)
+{
+  HALSIM_SetREVPHPressureSwitch(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    registerCompressorCurrentCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerCompressorCurrentCallback
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallback(env, index, callback, initialNotify,
+                               &HALSIM_RegisterREVPHCompressorCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    cancelCompressorCurrentCallback
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_cancelCompressorCurrentCallback
+  (JNIEnv* env, jclass, jint index, jint handle)
+{
+  return sim::FreeCallback(env, handle, index,
+                           &HALSIM_CancelREVPHCompressorCurrentCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    getCompressorCurrent
+ * Signature: (I)D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_getCompressorCurrent
+  (JNIEnv*, jclass, jint index)
+{
+  return HALSIM_GetREVPHCompressorCurrent(index);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    setCompressorCurrent
+ * Signature: (ID)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_setCompressorCurrent
+  (JNIEnv*, jclass, jint index, jdouble value)
+{
+  HALSIM_SetREVPHCompressorCurrent(index, value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    registerAllNonSolenoidCallbacks
+ * Signature: (ILjava/lang/Object;Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerAllNonSolenoidCallbacks
+  (JNIEnv* env, jclass, jint index, jobject callback, jboolean initialNotify)
+{
+  sim::AllocateCallback(
+      env, index, callback, initialNotify,
+      [](int32_t index, HAL_NotifyCallback cb, void* param, HAL_Bool in) {
+        HALSIM_RegisterREVPHAllNonSolenoidCallbacks(index, cb, param, in);
+        return 0;
+      });
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    registerAllSolenoidCallbacks
+ * Signature: (IILjava/lang/Object;Z)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_registerAllSolenoidCallbacks
+  (JNIEnv* env, jclass, jint index, jint channel, jobject callback,
+   jboolean initialNotify)
+{
+  sim::AllocateChannelCallback(
+      env, index, channel, callback, initialNotify,
+      [](int32_t index, int32_t channel, HAL_NotifyCallback cb, void* param,
+         HAL_Bool in) {
+        HALSIM_RegisterREVPHAllSolenoidCallbacks(index, channel, cb, param, in);
+        return 0;
+      });
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_REVPHDataJNI
+ * Method:    resetData
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_REVPHDataJNI_resetData
+  (JNIEnv*, jclass, jint index)
+{
+  HALSIM_ResetREVPHData(index);
+}
+
+}  // extern "C"
diff --git a/hal/src/main/native/cpp/jni/simulation/RelayDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/RelayDataJNI.cpp
index 7abe7cb..7a59327 100644
--- a/hal/src/main/native/cpp/jni/simulation/RelayDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/RelayDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp
index 1ff6044..03bb0c5 100644
--- a/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.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 <jni.h>
 
@@ -779,6 +776,57 @@
 
 /*
  * Class:     edu_wpi_first_hal_simulation_RoboRioDataJNI
+ * Method:    registerBrownoutVoltageCallback
+ * Signature: (Ljava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_registerBrownoutVoltageCallback
+  (JNIEnv* env, jclass, jobject callback, jboolean initialNotify)
+{
+  return sim::AllocateCallbackNoIndex(
+      env, callback, initialNotify,
+      &HALSIM_RegisterRoboRioBrownoutVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_RoboRioDataJNI
+ * Method:    cancelBrownoutVoltageCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_cancelBrownoutVoltageCallback
+  (JNIEnv* env, jclass, jint handle)
+{
+  return sim::FreeCallbackNoIndex(env, handle,
+                                  &HALSIM_CancelRoboRioBrownoutVoltageCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_RoboRioDataJNI
+ * Method:    getBrownoutVoltage
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL
+Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_getBrownoutVoltage
+  (JNIEnv*, jclass)
+{
+  return HALSIM_GetRoboRioBrownoutVoltage();
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_RoboRioDataJNI
+ * Method:    setBrownoutVoltage
+ * Signature: (D)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_setBrownoutVoltage
+  (JNIEnv*, jclass, jdouble value)
+{
+  HALSIM_SetRoboRioBrownoutVoltage(value);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_RoboRioDataJNI
  * Method:    resetData
  * Signature: ()V
  */
diff --git a/hal/src/main/native/cpp/jni/simulation/SPIAccelerometerDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/SPIAccelerometerDataJNI.cpp
index fe0c410..51bb320 100644
--- a/hal/src/main/native/cpp/jni/simulation/SPIAccelerometerDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/SPIAccelerometerDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/SPIDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/SPIDataJNI.cpp
index 3709984..977f25b 100644
--- a/hal/src/main/native/cpp/jni/simulation/SPIDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/SPIDataJNI.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 <jni.h>
 
diff --git a/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp
index 0b43d24..60ce0f7 100644
--- a/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp
@@ -1,23 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "SimDeviceDataJNI.h"
 
 #include <jni.h>
 
-#include <functional>
-#include <string>
+#include <cstdio>
 #include <utility>
 
-#include <wpi/UidVector.h>
 #include <wpi/jni_util.h>
 
 #include "SimulatorJNI.h"
 #include "edu_wpi_first_hal_simulation_SimDeviceDataJNI.h"
+#include "hal/SimDevice.h"
+#include "hal/handles/UnlimitedHandleResource.h"
 #include "hal/simulation/SimDeviceData.h"
 
 using namespace hal;
@@ -39,23 +36,18 @@
   HAL_SimValueHandle handle;
 
   jobject MakeJava(JNIEnv* env) const;
-  void CallJava(JNIEnv* env, jobject callobj) const;
 };
 
 struct ValueInfo {
-  ValueInfo(const char* name_, HAL_SimValueHandle handle_, bool readonly_,
+  ValueInfo(const char* name_, HAL_SimValueHandle handle_, int32_t direction_,
             const HAL_Value& value_)
-      : name{name_}, handle{handle_}, readonly{readonly_}, value{value_} {}
+      : name{name_}, handle{handle_}, direction{direction_}, value{value_} {}
   std::string name;
   HAL_SimValueHandle handle;
-  bool readonly;
+  int32_t direction;
   HAL_Value value;
 
   jobject MakeJava(JNIEnv* env) const;
-  void CallJava(JNIEnv* env, jobject callobj) const;
-
- private:
-  std::pair<jlong, jdouble> ToValue12() const;
 };
 
 }  // namespace
@@ -64,15 +56,10 @@
   static jmethodID func =
       env->GetMethodID(simDeviceInfoCls, "<init>", "(Ljava/lang/String;I)V");
   return env->NewObject(simDeviceInfoCls, func, MakeJString(env, name),
-                        (jint)handle);
+                        static_cast<jint>(handle));
 }
 
-void DeviceInfo::CallJava(JNIEnv* env, jobject callobj) const {
-  env->CallVoidMethod(callobj, simDeviceCallbackCallback,
-                      MakeJString(env, name), (jint)handle);
-}
-
-std::pair<jlong, jdouble> ValueInfo::ToValue12() const {
+static std::pair<jlong, jdouble> ToValue12(const HAL_Value& value) {
   jlong value1 = 0;
   jdouble value2 = 0.0;
   switch (value.type) {
@@ -99,194 +86,268 @@
 
 jobject ValueInfo::MakeJava(JNIEnv* env) const {
   static jmethodID func =
-      env->GetMethodID(simValueInfoCls, "<init>", "(Ljava/lang/String;IZIJD)V");
-  auto [value1, value2] = ToValue12();
+      env->GetMethodID(simValueInfoCls, "<init>", "(Ljava/lang/String;IIIJD)V");
+  auto [value1, value2] = ToValue12(value);
   return env->NewObject(simValueInfoCls, func, MakeJString(env, name),
-                        (jint)handle, (jboolean)readonly, (jint)value.type,
-                        value1, value2);
-}
-
-void ValueInfo::CallJava(JNIEnv* env, jobject callobj) const {
-  auto [value1, value2] = ToValue12();
-  env->CallVoidMethod(callobj, simValueCallbackCallback, MakeJString(env, name),
-                      (jint)handle, (jboolean)readonly, (jint)value.type,
-                      value1, value2);
+                        static_cast<jint>(handle), static_cast<jint>(direction),
+                        static_cast<jint>(value.type), value1, value2);
 }
 
 namespace {
 
-class CallbackStore {
+class DeviceCallbackStore {
  public:
-  explicit CallbackStore(JNIEnv* env, jobject obj) : m_call{env, obj} {}
-  ~CallbackStore() {
-    if (m_cancelCallback) m_cancelCallback();
-  }
-
-  void SetCancel(std::function<void()> cancelCallback) {
-    m_cancelCallback = std::move(cancelCallback);
-  }
-  void Free(JNIEnv* env) { m_call.free(env); }
-  jobject Get() const { return m_call; }
+  void create(JNIEnv* env, jobject obj) { m_call = JGlobal<jobject>(env, obj); }
+  void performCallback(const char* name, HAL_SimDeviceHandle handle);
+  void free(JNIEnv* env) { m_call.free(env); }
+  void setCallbackId(int32_t id) { callbackId = id; }
+  int32_t getCallbackId() { return callbackId; }
 
  private:
   wpi::java::JGlobal<jobject> m_call;
-  std::function<void()> m_cancelCallback;
+  int32_t callbackId;
 };
 
-class CallbackThreadJNI : public wpi::SafeThread {
+class ValueCallbackStore {
  public:
-  void Main();
-
-  using DeviceCalls =
-      std::vector<std::pair<std::weak_ptr<CallbackStore>, DeviceInfo>>;
-  DeviceCalls m_deviceCalls;
-  using ValueCalls =
-      std::vector<std::pair<std::weak_ptr<CallbackStore>, ValueInfo>>;
-  ValueCalls m_valueCalls;
-
-  wpi::UidVector<std::shared_ptr<CallbackStore>, 4> m_callbacks;
-};
-
-class CallbackJNI {
- public:
-  static CallbackJNI& GetInstance() {
-    static CallbackJNI inst;
-    return inst;
-  }
-  void SendDevice(int32_t callback, DeviceInfo info);
-  void SendValue(int32_t callback, ValueInfo info);
-
-  std::pair<int32_t, std::shared_ptr<CallbackStore>> AllocateCallback(
-      JNIEnv* env, jobject obj);
-
-  void FreeCallback(JNIEnv* env, int32_t uid);
+  void create(JNIEnv* env, jobject obj) { m_call = JGlobal<jobject>(env, obj); }
+  void performCallback(const char* name, HAL_SimValueHandle handle,
+                       int32_t direction, const HAL_Value& value);
+  void free(JNIEnv* env) { m_call.free(env); }
+  void setCallbackId(int32_t id) { m_callbackId = id; }
+  int32_t getCallbackId() { return m_callbackId; }
 
  private:
-  CallbackJNI() { m_owner.Start(); }
-
-  wpi::SafeThreadOwner<CallbackThreadJNI> m_owner;
+  wpi::java::JGlobal<jobject> m_call;
+  int32_t m_callbackId;
 };
 
 }  // namespace
 
-void CallbackThreadJNI::Main() {
+void DeviceCallbackStore::performCallback(const char* name,
+                                          HAL_SimDeviceHandle handle) {
   JNIEnv* env;
-  JavaVMAttachArgs args;
-  args.version = JNI_VERSION_1_2;
-  args.name = const_cast<char*>("SimDeviceCallback");
-  args.group = nullptr;
-  jint rs = sim::GetJVM()->AttachCurrentThreadAsDaemon(
-      reinterpret_cast<void**>(&env), &args);
-  if (rs != JNI_OK) return;
-
-  DeviceCalls deviceCalls;
-  ValueCalls valueCalls;
-
-  std::unique_lock lock(m_mutex);
-  while (m_active) {
-    m_cond.wait(lock, [&] { return !m_active; });
-    if (!m_active) break;
-
-    deviceCalls.swap(m_deviceCalls);
-    valueCalls.swap(m_valueCalls);
-
-    lock.unlock();  // don't hold mutex during callback execution
-
-    for (auto&& call : deviceCalls) {
-      if (auto store = call.first.lock()) {
-        if (jobject callobj = store->Get()) {
-          call.second.CallJava(env, callobj);
-          if (env->ExceptionCheck()) {
-            env->ExceptionDescribe();
-            env->ExceptionClear();
-          }
-        }
-      }
+  JavaVM* vm = sim::GetJVM();
+  bool didAttachThread = false;
+  int tryGetEnv = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+  if (tryGetEnv == JNI_EDETACHED) {
+    // Thread not attached
+    didAttachThread = true;
+    if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
+      // Failed to attach, log and return
+      std::puts("Failed to attach");
+      std::fflush(stdout);
+      return;
     }
-
-    for (auto&& call : valueCalls) {
-      if (auto store = call.first.lock()) {
-        if (jobject callobj = store->Get()) {
-          call.second.CallJava(env, callobj);
-          if (env->ExceptionCheck()) {
-            env->ExceptionDescribe();
-            env->ExceptionClear();
-          }
-        }
-      }
-    }
-
-    deviceCalls.clear();
-    valueCalls.clear();
-
-    lock.lock();
+  } else if (tryGetEnv == JNI_EVERSION) {
+    std::puts("Invalid JVM Version requested");
+    std::fflush(stdout);
   }
 
-  // free global references
-  for (auto&& callback : m_callbacks) callback->Free(env);
+  env->CallVoidMethod(m_call, simDeviceCallbackCallback, MakeJString(env, name),
+                      static_cast<jint>(handle));
 
-  sim::GetJVM()->DetachCurrentThread();
+  if (env->ExceptionCheck()) {
+    env->ExceptionDescribe();
+  }
+
+  if (didAttachThread) {
+    vm->DetachCurrentThread();
+  }
 }
 
-void CallbackJNI::SendDevice(int32_t callback, DeviceInfo info) {
-  auto thr = m_owner.GetThread();
-  if (!thr) return;
-  thr->m_deviceCalls.emplace_back(thr->m_callbacks[callback], std::move(info));
-  thr->m_cond.notify_one();
+void ValueCallbackStore::performCallback(const char* name,
+                                         HAL_SimValueHandle handle,
+                                         int32_t direction,
+                                         const HAL_Value& value) {
+  JNIEnv* env;
+  JavaVM* vm = sim::GetJVM();
+  bool didAttachThread = false;
+  int tryGetEnv = vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+  if (tryGetEnv == JNI_EDETACHED) {
+    // Thread not attached
+    didAttachThread = true;
+    if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
+      // Failed to attach, log and return
+      std::puts("Failed to attach");
+      std::fflush(stdout);
+      return;
+    }
+  } else if (tryGetEnv == JNI_EVERSION) {
+    std::puts("Invalid JVM Version requested");
+    std::fflush(stdout);
+  }
+
+  auto [value1, value2] = ToValue12(value);
+  env->CallVoidMethod(m_call, simValueCallbackCallback, MakeJString(env, name),
+                      static_cast<jint>(handle), static_cast<jint>(direction),
+                      static_cast<jint>(value.type), value1, value2);
+
+  if (env->ExceptionCheck()) {
+    env->ExceptionDescribe();
+  }
+
+  if (didAttachThread) {
+    vm->DetachCurrentThread();
+  }
 }
 
-void CallbackJNI::SendValue(int32_t callback, ValueInfo info) {
-  auto thr = m_owner.GetThread();
-  if (!thr) return;
-  thr->m_valueCalls.emplace_back(thr->m_callbacks[callback], std::move(info));
-  thr->m_cond.notify_one();
+static hal::UnlimitedHandleResource<SIM_JniHandle, DeviceCallbackStore,
+                                    hal::HAL_HandleEnum::SimulationJni>*
+    deviceCallbackHandles;
+
+namespace {
+using RegisterDeviceCallbackFunc =
+    int32_t (*)(const char* prefix, void* param,
+                HALSIM_SimDeviceCallback callback, HAL_Bool initialNotify);
+using FreeDeviceCallbackFunc = void (*)(int32_t uid);
+}  // namespace
+
+static SIM_JniHandle AllocateDeviceCallback(
+    JNIEnv* env, const char* prefix, jobject callback, jboolean initialNotify,
+    RegisterDeviceCallbackFunc createCallback) {
+  auto callbackStore = std::make_shared<DeviceCallbackStore>();
+
+  auto handle = deviceCallbackHandles->Allocate(callbackStore);
+
+  if (handle == HAL_kInvalidHandle) {
+    return -1;
+  }
+
+  uintptr_t handleAsPtr = static_cast<uintptr_t>(handle);
+  void* handleAsVoidPtr = reinterpret_cast<void*>(handleAsPtr);
+
+  callbackStore->create(env, callback);
+
+  auto callbackFunc = [](const char* name, void* param,
+                         HAL_SimDeviceHandle handle) {
+    uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+    SIM_JniHandle jnihandle = static_cast<SIM_JniHandle>(handleTmp);
+    auto data = deviceCallbackHandles->Get(jnihandle);
+    if (!data) {
+      return;
+    }
+
+    data->performCallback(name, handle);
+  };
+
+  auto id =
+      createCallback(prefix, handleAsVoidPtr, callbackFunc, initialNotify);
+
+  callbackStore->setCallbackId(id);
+
+  return handle;
 }
 
-std::pair<int32_t, std::shared_ptr<CallbackStore>>
-CallbackJNI::AllocateCallback(JNIEnv* env, jobject obj) {
-  auto thr = m_owner.GetThread();
-  if (!thr) return std::pair(0, nullptr);
-  auto store = std::make_shared<CallbackStore>(env, obj);
-  return std::pair(thr->m_callbacks.emplace_back(store) + 1, store);
+static void FreeDeviceCallback(JNIEnv* env, SIM_JniHandle handle,
+                               FreeDeviceCallbackFunc freeCallback) {
+  auto callback = deviceCallbackHandles->Free(handle);
+  freeCallback(callback->getCallbackId());
+  callback->free(env);
 }
 
-void CallbackJNI::FreeCallback(JNIEnv* env, int32_t uid) {
-  auto thr = m_owner.GetThread();
-  if (!thr) return;
-  if (uid <= 0 || static_cast<uint32_t>(uid) >= thr->m_callbacks.size()) return;
-  --uid;
-  auto store = std::move(thr->m_callbacks[uid]);
-  thr->m_callbacks.erase(uid);
-  store->Free(env);
+static hal::UnlimitedHandleResource<SIM_JniHandle, ValueCallbackStore,
+                                    hal::HAL_HandleEnum::SimulationJni>*
+    valueCallbackHandles;
+
+namespace {
+using FreeValueCallbackFunc = void (*)(int32_t uid);
+}  // namespace
+
+template <typename THandle>
+static SIM_JniHandle AllocateValueCallback(
+    JNIEnv* env, THandle h, jobject callback, jboolean initialNotify,
+    int32_t (*createCallback)(THandle handle, void* param,
+                              HALSIM_SimValueCallback callback,
+                              HAL_Bool initialNotify)) {
+  auto callbackStore = std::make_shared<ValueCallbackStore>();
+
+  auto handle = valueCallbackHandles->Allocate(callbackStore);
+
+  if (handle == HAL_kInvalidHandle) {
+    return -1;
+  }
+
+  uintptr_t handleAsPtr = static_cast<uintptr_t>(handle);
+  void* handleAsVoidPtr = reinterpret_cast<void*>(handleAsPtr);
+
+  callbackStore->create(env, callback);
+
+  auto callbackFunc = [](const char* name, void* param,
+                         HAL_SimValueHandle handle, int32_t direction,
+                         const HAL_Value* value) {
+    uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
+    SIM_JniHandle jnihandle = static_cast<SIM_JniHandle>(handleTmp);
+    auto data = valueCallbackHandles->Get(jnihandle);
+    if (!data) {
+      return;
+    }
+
+    data->performCallback(name, handle, direction, *value);
+  };
+
+  auto id = createCallback(h, handleAsVoidPtr, callbackFunc, initialNotify);
+
+  callbackStore->setCallbackId(id);
+
+  return handle;
 }
 
-namespace hal {
-namespace sim {
+static void FreeValueCallback(JNIEnv* env, SIM_JniHandle handle,
+                              FreeValueCallbackFunc freeCallback) {
+  auto callback = valueCallbackHandles->Free(handle);
+  freeCallback(callback->getCallbackId());
+  callback->free(env);
+}
+
+namespace hal::sim {
 
 bool InitializeSimDeviceDataJNI(JNIEnv* env) {
   simDeviceInfoCls = JClass(
       env, "edu/wpi/first/hal/simulation/SimDeviceDataJNI$SimDeviceInfo");
-  if (!simDeviceInfoCls) return false;
+  if (!simDeviceInfoCls) {
+    return false;
+  }
 
   simValueInfoCls =
       JClass(env, "edu/wpi/first/hal/simulation/SimDeviceDataJNI$SimValueInfo");
-  if (!simValueInfoCls) return false;
+  if (!simValueInfoCls) {
+    return false;
+  }
 
   simDeviceCallbackCls =
       JClass(env, "edu/wpi/first/hal/simulation/SimDeviceCallback");
-  if (!simDeviceCallbackCls) return false;
+  if (!simDeviceCallbackCls) {
+    return false;
+  }
 
   simDeviceCallbackCallback = env->GetMethodID(simDeviceCallbackCls, "callback",
                                                "(Ljava/lang/String;I)V");
-  if (!simDeviceCallbackCallback) return false;
+  if (!simDeviceCallbackCallback) {
+    return false;
+  }
 
   simValueCallbackCls =
       JClass(env, "edu/wpi/first/hal/simulation/SimValueCallback");
-  if (!simValueCallbackCls) return false;
+  if (!simValueCallbackCls) {
+    return false;
+  }
 
   simValueCallbackCallback = env->GetMethodID(
-      simValueCallbackCls, "callbackNative", "(Ljava/lang/String;IZIJD)V");
-  if (!simValueCallbackCallback) return false;
+      simValueCallbackCls, "callbackNative", "(Ljava/lang/String;IIIJD)V");
+  if (!simValueCallbackCallback) {
+    return false;
+  }
+
+  static hal::UnlimitedHandleResource<SIM_JniHandle, DeviceCallbackStore,
+                                      hal::HAL_HandleEnum::SimulationJni>
+      cbDevice;
+  deviceCallbackHandles = &cbDevice;
+
+  static hal::UnlimitedHandleResource<SIM_JniHandle, ValueCallbackStore,
+                                      hal::HAL_HandleEnum::SimulationJni>
+      cbValue;
+  valueCallbackHandles = &cbValue;
 
   return true;
 }
@@ -298,8 +359,7 @@
   simValueCallbackCls.free(env);
 }
 
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
 
 extern "C" {
 
@@ -337,18 +397,9 @@
   (JNIEnv* env, jclass, jstring prefix, jobject callback,
    jboolean initialNotify)
 {
-  auto [uid, store] =
-      CallbackJNI::GetInstance().AllocateCallback(env, callback);
-  int32_t cuid = HALSIM_RegisterSimDeviceCreatedCallback(
-      JStringRef{env, prefix}.c_str(),
-      reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
-      [](const char* name, void* param, HAL_SimDeviceHandle handle) {
-        int32_t uid = reinterpret_cast<intptr_t>(param);
-        CallbackJNI::GetInstance().SendDevice(uid, DeviceInfo{name, handle});
-      },
-      initialNotify);
-  store->SetCancel([cuid] { HALSIM_CancelSimDeviceCreatedCallback(cuid); });
-  return uid;
+  return AllocateDeviceCallback(env, JStringRef{env, prefix}.c_str(), callback,
+                                initialNotify,
+                                &HALSIM_RegisterSimDeviceCreatedCallback);
 }
 
 /*
@@ -360,29 +411,22 @@
 Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_cancelSimDeviceCreatedCallback
   (JNIEnv* env, jclass, jint uid)
 {
-  CallbackJNI::GetInstance().FreeCallback(env, uid);
+  FreeDeviceCallback(env, uid, &HALSIM_CancelSimDeviceCreatedCallback);
 }
 
 /*
  * Class:     edu_wpi_first_hal_simulation_SimDeviceDataJNI
  * Method:    registerSimDeviceFreedCallback
- * Signature: (Ljava/lang/String;Ljava/lang/Object;)I
+ * Signature: (Ljava/lang/String;Ljava/lang/Object;Z)I
  */
 JNIEXPORT jint JNICALL
 Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimDeviceFreedCallback
-  (JNIEnv* env, jclass, jstring prefix, jobject callback)
+  (JNIEnv* env, jclass, jstring prefix, jobject callback,
+   jboolean initialNotify)
 {
-  auto [uid, store] =
-      CallbackJNI::GetInstance().AllocateCallback(env, callback);
-  int32_t cuid = HALSIM_RegisterSimDeviceFreedCallback(
-      JStringRef{env, prefix}.c_str(),
-      reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
-      [](const char* name, void* param, HAL_SimDeviceHandle handle) {
-        int32_t uid = reinterpret_cast<intptr_t>(param);
-        CallbackJNI::GetInstance().SendDevice(uid, DeviceInfo{name, handle});
-      });
-  store->SetCancel([cuid] { HALSIM_CancelSimDeviceFreedCallback(cuid); });
-  return uid;
+  return AllocateDeviceCallback(env, JStringRef{env, prefix}.c_str(), callback,
+                                initialNotify,
+                                &HALSIM_RegisterSimDeviceFreedCallback);
 }
 
 /*
@@ -394,7 +438,7 @@
 Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_cancelSimDeviceFreedCallback
   (JNIEnv* env, jclass, jint uid)
 {
-  CallbackJNI::GetInstance().FreeCallback(env, uid);
+  FreeDeviceCallback(env, uid, &HALSIM_CancelSimDeviceFreedCallback);
 }
 
 /*
@@ -411,6 +455,18 @@
 
 /*
  * Class:     edu_wpi_first_hal_simulation_SimDeviceDataJNI
+ * Method:    getSimDeviceName
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_getSimDeviceName
+  (JNIEnv* env, jclass, jint handle)
+{
+  return MakeJString(env, HALSIM_GetSimDeviceName(handle));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_SimDeviceDataJNI
  * Method:    getSimValueDeviceHandle
  * Signature: (I)I
  */
@@ -443,7 +499,9 @@
   size_t numElems = arr.size();
   jobjectArray jarr =
       env->NewObjectArray(arr.size(), simDeviceInfoCls, nullptr);
-  if (!jarr) return nullptr;
+  if (!jarr) {
+    return nullptr;
+  }
   for (size_t i = 0; i < numElems; ++i) {
     JLocal<jobject> elem{env, arr[i].MakeJava(env)};
     env->SetObjectArrayElement(jarr, i, elem.obj());
@@ -460,19 +518,9 @@
 Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimValueCreatedCallback
   (JNIEnv* env, jclass, jint device, jobject callback, jboolean initialNotify)
 {
-  auto [uid, store] =
-      CallbackJNI::GetInstance().AllocateCallback(env, callback);
-  int32_t cuid = HALSIM_RegisterSimValueCreatedCallback(
-      device, reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
-      [](const char* name, void* param, HAL_SimValueHandle handle,
-         HAL_Bool readonly, const HAL_Value* value) {
-        int32_t uid = reinterpret_cast<intptr_t>(param);
-        CallbackJNI::GetInstance().SendValue(
-            uid, ValueInfo{name, handle, static_cast<bool>(readonly), *value});
-      },
-      initialNotify);
-  store->SetCancel([cuid] { HALSIM_CancelSimValueCreatedCallback(cuid); });
-  return uid;
+  return AllocateValueCallback(env, static_cast<HAL_SimDeviceHandle>(device),
+                               callback, initialNotify,
+                               &HALSIM_RegisterSimValueCreatedCallback);
 }
 
 /*
@@ -484,7 +532,7 @@
 Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_cancelSimValueCreatedCallback
   (JNIEnv* env, jclass, jint uid)
 {
-  CallbackJNI::GetInstance().FreeCallback(env, uid);
+  FreeValueCallback(env, uid, &HALSIM_CancelSimValueCreatedCallback);
 }
 
 /*
@@ -496,19 +544,9 @@
 Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimValueChangedCallback
   (JNIEnv* env, jclass, jint handle, jobject callback, jboolean initialNotify)
 {
-  auto [uid, store] =
-      CallbackJNI::GetInstance().AllocateCallback(env, callback);
-  int32_t cuid = HALSIM_RegisterSimValueChangedCallback(
-      handle, reinterpret_cast<void*>(static_cast<intptr_t>(uid)),
-      [](const char* name, void* param, HAL_SimValueHandle handle,
-         HAL_Bool readonly, const HAL_Value* value) {
-        int32_t uid = reinterpret_cast<intptr_t>(param);
-        CallbackJNI::GetInstance().SendValue(
-            uid, ValueInfo{name, handle, static_cast<bool>(readonly), *value});
-      },
-      initialNotify);
-  store->SetCancel([cuid] { HALSIM_CancelSimValueChangedCallback(cuid); });
-  return uid;
+  return AllocateValueCallback(env, static_cast<HAL_SimValueHandle>(handle),
+                               callback, initialNotify,
+                               &HALSIM_RegisterSimValueChangedCallback);
 }
 
 /*
@@ -520,7 +558,33 @@
 Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_cancelSimValueChangedCallback
   (JNIEnv* env, jclass, jint uid)
 {
-  CallbackJNI::GetInstance().FreeCallback(env, uid);
+  FreeValueCallback(env, uid, &HALSIM_CancelSimValueChangedCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_SimDeviceDataJNI
+ * Method:    registerSimValueResetCallback
+ * Signature: (ILjava/lang/Object;Z)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimValueResetCallback
+  (JNIEnv* env, jclass, jint handle, jobject callback, jboolean initialNotify)
+{
+  return AllocateValueCallback(env, static_cast<HAL_SimValueHandle>(handle),
+                               callback, initialNotify,
+                               &HALSIM_RegisterSimValueResetCallback);
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_SimDeviceDataJNI
+ * Method:    cancelSimValueResetCallback
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_cancelSimValueResetCallback
+  (JNIEnv* env, jclass, jint uid)
+{
+  FreeValueCallback(env, uid, &HALSIM_CancelSimValueResetCallback);
 }
 
 /*
@@ -557,7 +621,9 @@
   // convert to java
   size_t numElems = arr.size();
   jobjectArray jarr = env->NewObjectArray(arr.size(), simValueInfoCls, nullptr);
-  if (!jarr) return nullptr;
+  if (!jarr) {
+    return nullptr;
+  }
   for (size_t i = 0; i < numElems; ++i) {
     JLocal<jobject> elem{env, arr[i].MakeJava(env)};
     env->SetObjectArrayElement(jarr, i, elem.obj());
@@ -575,11 +641,15 @@
   (JNIEnv* env, jclass, jint handle)
 {
   static JClass stringCls{env, "java/lang/String"};
-  if (!stringCls) return nullptr;
+  if (!stringCls) {
+    return nullptr;
+  }
   int32_t numElems = 0;
   const char** elems = HALSIM_GetSimValueEnumOptions(handle, &numElems);
   jobjectArray jarr = env->NewObjectArray(numElems, stringCls, nullptr);
-  if (!jarr) return nullptr;
+  if (!jarr) {
+    return nullptr;
+  }
   for (int32_t i = 0; i < numElems; ++i) {
     JLocal<jstring> elem{env, MakeJString(env, elems[i])};
     env->SetObjectArrayElement(jarr, i, elem.obj());
@@ -589,6 +659,20 @@
 
 /*
  * Class:     edu_wpi_first_hal_simulation_SimDeviceDataJNI
+ * Method:    getSimValueEnumDoubleValues
+ * Signature: (I)[D
+ */
+JNIEXPORT jdoubleArray JNICALL
+Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_getSimValueEnumDoubleValues
+  (JNIEnv* env, jclass, jint handle)
+{
+  int32_t numElems = 0;
+  const double* elems = HALSIM_GetSimValueEnumDoubleValues(handle, &numElems);
+  return MakeJDoubleArray(env, wpi::span(elems, numElems));
+}
+
+/*
+ * Class:     edu_wpi_first_hal_simulation_SimDeviceDataJNI
  * Method:    resetSimDeviceData
  * Signature: ()V
  */
diff --git a/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.h b/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.h
index 44fc27f..08c47b9 100644
--- a/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.h
+++ b/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.h
@@ -1,17 +1,12 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
 #include <jni.h>
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 bool InitializeSimDeviceDataJNI(JNIEnv* env);
 void FreeSimDeviceDataJNI(JNIEnv* env);
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
diff --git a/hal/src/main/native/cpp/jni/simulation/SimulatorJNI.cpp b/hal/src/main/native/cpp/jni/simulation/SimulatorJNI.cpp
index b6336e8..859c7f5 100644
--- a/hal/src/main/native/cpp/jni/simulation/SimulatorJNI.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/SimulatorJNI.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 "SimulatorJNI.h"
 
@@ -31,61 +28,80 @@
 static jmethodID constBufferCallbackCallback;
 static jmethodID spiReadAutoReceiveBufferCallbackCallback;
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 jint SimOnLoad(JavaVM* vm, void* reserved) {
   jvm = vm;
 
   JNIEnv* env;
-  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
     return JNI_ERR;
+  }
 
   notifyCallbackCls =
       JClass(env, "edu/wpi/first/hal/simulation/NotifyCallback");
-  if (!notifyCallbackCls) return JNI_ERR;
+  if (!notifyCallbackCls) {
+    return JNI_ERR;
+  }
 
   notifyCallbackCallback = env->GetMethodID(notifyCallbackCls, "callbackNative",
                                             "(Ljava/lang/String;IJD)V");
-  if (!notifyCallbackCallback) return JNI_ERR;
+  if (!notifyCallbackCallback) {
+    return JNI_ERR;
+  }
 
   bufferCallbackCls =
       JClass(env, "edu/wpi/first/hal/simulation/BufferCallback");
-  if (!bufferCallbackCls) return JNI_ERR;
+  if (!bufferCallbackCls) {
+    return JNI_ERR;
+  }
 
   bufferCallbackCallback = env->GetMethodID(bufferCallbackCls, "callback",
                                             "(Ljava/lang/String;[BI)V");
-  if (!bufferCallbackCallback) return JNI_ERR;
+  if (!bufferCallbackCallback) {
+    return JNI_ERR;
+  }
 
   constBufferCallbackCls =
       JClass(env, "edu/wpi/first/hal/simulation/ConstBufferCallback");
-  if (!constBufferCallbackCls) return JNI_ERR;
+  if (!constBufferCallbackCls) {
+    return JNI_ERR;
+  }
 
   constBufferCallbackCallback = env->GetMethodID(
       constBufferCallbackCls, "callback", "(Ljava/lang/String;[BI)V");
-  if (!constBufferCallbackCallback) return JNI_ERR;
+  if (!constBufferCallbackCallback) {
+    return JNI_ERR;
+  }
 
   spiReadAutoReceiveBufferCallbackCls = JClass(
       env, "edu/wpi/first/hal/simulation/SpiReadAutoReceiveBufferCallback");
-  if (!spiReadAutoReceiveBufferCallbackCls) return JNI_ERR;
+  if (!spiReadAutoReceiveBufferCallbackCls) {
+    return JNI_ERR;
+  }
 
   spiReadAutoReceiveBufferCallbackCallback =
       env->GetMethodID(spiReadAutoReceiveBufferCallbackCls, "callback",
                        "(Ljava/lang/String;[II)I");
-  if (!spiReadAutoReceiveBufferCallbackCallback) return JNI_ERR;
+  if (!spiReadAutoReceiveBufferCallbackCallback) {
+    return JNI_ERR;
+  }
 
   InitializeStore();
   InitializeBufferStore();
   InitializeConstBufferStore();
   InitializeSpiBufferStore();
-  if (!InitializeSimDeviceDataJNI(env)) return JNI_ERR;
+  if (!InitializeSimDeviceDataJNI(env)) {
+    return JNI_ERR;
+  }
 
   return JNI_VERSION_1_6;
 }
 
 void SimOnUnload(JavaVM* vm, void* reserved) {
   JNIEnv* env;
-  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
     return;
+  }
 
   notifyCallbackCls.free(env);
   bufferCallbackCls.free(env);
@@ -95,19 +111,26 @@
   jvm = nullptr;
 }
 
-JavaVM* GetJVM() { return jvm; }
+JavaVM* GetJVM() {
+  return jvm;
+}
 
-jmethodID GetNotifyCallback() { return notifyCallbackCallback; }
+jmethodID GetNotifyCallback() {
+  return notifyCallbackCallback;
+}
 
-jmethodID GetBufferCallback() { return bufferCallbackCallback; }
+jmethodID GetBufferCallback() {
+  return bufferCallbackCallback;
+}
 
-jmethodID GetConstBufferCallback() { return constBufferCallbackCallback; }
+jmethodID GetConstBufferCallback() {
+  return constBufferCallbackCallback;
+}
 
 jmethodID GetSpiReadAutoReceiveBufferCallback() {
   return spiReadAutoReceiveBufferCallbackCallback;
 }
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
 
 extern "C" {
 /*
diff --git a/hal/src/main/native/cpp/jni/simulation/SimulatorJNI.h b/hal/src/main/native/cpp/jni/simulation/SimulatorJNI.h
index d6710e8..3e71acd 100644
--- a/hal/src/main/native/cpp/jni/simulation/SimulatorJNI.h
+++ b/hal/src/main/native/cpp/jni/simulation/SimulatorJNI.h
@@ -1,24 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
 #include "hal/Types.h"
 #include "jni.h"
 
-typedef HAL_Handle SIM_JniHandle;
+using SIM_JniHandle = HAL_Handle;  // NOLINT
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 JavaVM* GetJVM();
 
 jmethodID GetNotifyCallback();
 jmethodID GetBufferCallback();
 jmethodID GetConstBufferCallback();
 jmethodID GetSpiReadAutoReceiveBufferCallback();
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
diff --git a/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.cpp b/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.cpp
index 5432840..c20f607 100644
--- a/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.cpp
+++ b/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.cpp
@@ -1,14 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "SpiReadAutoReceiveBufferCallbackStore.h"
 
 #include <jni.h>
 
+#include <cstdio>
+
 #include <wpi/jni_util.h>
 
 #include "SimulatorJNI.h"
@@ -25,8 +24,7 @@
     SIM_JniHandle, SpiReadAutoReceiveBufferCallbackStore,
     hal::HAL_HandleEnum::SimulationJni>* callbackHandles;
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 void InitializeSpiBufferStore() {
   static hal::UnlimitedHandleResource<SIM_JniHandle,
                                       SpiReadAutoReceiveBufferCallbackStore,
@@ -34,8 +32,7 @@
       cb;
   callbackHandles = &cb;
 }
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
 
 void SpiReadAutoReceiveBufferCallbackStore::create(JNIEnv* env, jobject obj) {
   m_call = JGlobal<jobject>(env, obj);
@@ -52,21 +49,21 @@
     didAttachThread = true;
     if (vm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) != 0) {
       // Failed to attach, log and return
-      wpi::outs() << "Failed to attach\n";
-      wpi::outs().flush();
+      std::puts("Failed to attach");
+      std::fflush(stdout);
       return -1;
     }
   } else if (tryGetEnv == JNI_EVERSION) {
-    wpi::outs() << "Invalid JVM Version requested\n";
-    wpi::outs().flush();
+    std::puts("Invalid JVM Version requested");
+    std::fflush(stdout);
   }
 
   auto toCallbackArr = MakeJIntArray(
-      env, wpi::ArrayRef<uint32_t>{buffer, static_cast<size_t>(numToRead)});
+      env, wpi::span<const uint32_t>{buffer, static_cast<size_t>(numToRead)});
 
   jint ret = env->CallIntMethod(m_call, sim::GetBufferCallback(),
                                 MakeJString(env, name), toCallbackArr,
-                                (jint)numToRead);
+                                static_cast<jint>(numToRead));
 
   jint* fromCallbackArr = reinterpret_cast<jint*>(
       env->GetPrimitiveArrayCritical(toCallbackArr, nullptr));
@@ -113,7 +110,9 @@
     uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
     SIM_JniHandle handle = static_cast<SIM_JniHandle>(handleTmp);
     auto data = callbackHandles->Get(handle);
-    if (!data) return;
+    if (!data) {
+      return;
+    }
 
     *outputCount = data->performCallback(name, buffer, numToRead);
   };
diff --git a/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.h b/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.h
index 6a457de..18e8a44 100644
--- a/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.h
+++ b/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -18,8 +15,7 @@
 #include "hal/simulation/NotifyListener.h"
 #include "hal/simulation/SPIData.h"
 
-namespace hal {
-namespace sim {
+namespace hal::sim {
 class SpiReadAutoReceiveBufferCallbackStore {
  public:
   void create(JNIEnv* env, jobject obj);
@@ -36,14 +32,13 @@
 
 void InitializeSpiBufferStore();
 
-typedef int32_t (*RegisterSpiBufferCallbackFunc)(
+using RegisterSpiBufferCallbackFunc = int32_t (*)(
     int32_t index, HAL_SpiReadAutoReceiveBufferCallback callback, void* param);
-typedef void (*FreeSpiBufferCallbackFunc)(int32_t index, int32_t uid);
+using FreeSpiBufferCallbackFunc = void (*)(int32_t index, int32_t uid);
 
 SIM_JniHandle AllocateSpiBufferCallback(
     JNIEnv* env, jint index, jobject callback,
     RegisterSpiBufferCallbackFunc createCallback);
 void FreeSpiBufferCallback(JNIEnv* env, SIM_JniHandle handle, jint index,
                            FreeSpiBufferCallbackFunc freeCallback);
-}  // namespace sim
-}  // namespace hal
+}  // namespace hal::sim
diff --git a/hal/src/main/native/include/hal/.clang-tidy b/hal/src/main/native/include/hal/.clang-tidy
new file mode 100644
index 0000000..4f4edda
--- /dev/null
+++ b/hal/src/main/native/include/hal/.clang-tidy
@@ -0,0 +1,75 @@
+Checks:
+  'bugprone-assert-side-effect,
+  bugprone-bool-pointer-implicit-conversion,
+  bugprone-copy-constructor-init,
+  bugprone-dangling-handle,
+  bugprone-dynamic-static-initializers,
+  bugprone-exception-escape,
+  bugprone-forward-declaration-namespace,
+  bugprone-forwarding-reference-overload,
+  bugprone-inaccurate-erase,
+  bugprone-incorrect-roundings,
+  bugprone-integer-division,
+  bugprone-lambda-function-name,
+  bugprone-misplaced-operator-in-strlen-in-alloc,
+  bugprone-misplaced-widening-cast,
+  bugprone-move-forwarding-reference,
+  bugprone-multiple-statement-macro,
+  bugprone-parent-virtual-call,
+  bugprone-posix-return,
+  bugprone-sizeof-container,
+  bugprone-sizeof-expression,
+  bugprone-spuriously-wake-up-functions,
+  bugprone-string-constructor,
+  bugprone-string-integer-assignment,
+  bugprone-string-literal-with-embedded-nul,
+  bugprone-suspicious-enum-usage,
+  bugprone-suspicious-include,
+  bugprone-suspicious-memset-usage,
+  bugprone-suspicious-missing-comma,
+  bugprone-suspicious-semicolon,
+  bugprone-suspicious-string-compare,
+  bugprone-throw-keyword-missing,
+  bugprone-too-small-loop-variable,
+  bugprone-undefined-memory-manipulation,
+  bugprone-undelegated-constructor,
+  bugprone-unhandled-self-assignment,
+  bugprone-unused-raii,
+  bugprone-virtual-near-miss,
+  cert-dcl58-cpp,
+  cert-err52-cpp,
+  cert-err60-cpp,
+  cert-mem57-cpp,
+  cert-oop57-cpp,
+  cert-oop58-cpp,
+  clang-diagnostic-*,
+  -clang-diagnostic-deprecated-declarations,
+  -clang-diagnostic-#warnings,
+  -clang-diagnostic-pedantic,
+  clang-analyzer-*,
+  cppcoreguidelines-slicing,
+  google-build-namespaces,
+  google-explicit-constructor,
+  google-global-names-in-headers,
+  google-readability-avoid-underscore-in-googletest-name,
+  google-readability-casting,
+  google-runtime-operator,
+  llvm-twine-local,
+  misc-definitions-in-headers,
+  misc-misplaced-const,
+  misc-new-delete-overloads,
+  misc-non-copyable-objects,
+  modernize-avoid-bind,
+  modernize-concat-nested-namespaces,
+  modernize-make-shared,
+  modernize-make-unique,
+  modernize-pass-by-value,
+  modernize-use-default-member-init,
+  modernize-use-noexcept,
+  modernize-use-nullptr,
+  modernize-use-override,
+  readability-braces-around-statements'
+FormatStyle: file
+CheckOptions:
+  - key: bugprone-dangling-handle
+    value: 'std::string_view'
diff --git a/hal/src/main/native/include/hal/Accelerometer.h b/hal/src/main/native/include/hal/Accelerometer.h
index 9dc488b..9131e83 100644
--- a/hal/src/main/native/include/hal/Accelerometer.h
+++ b/hal/src/main/native/include/hal/Accelerometer.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/include/hal/AddressableLED.h b/hal/src/main/native/include/hal/AddressableLED.h
index 68383ef..7674979 100644
--- a/hal/src/main/native/include/hal/AddressableLED.h
+++ b/hal/src/main/native/include/hal/AddressableLED.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
diff --git a/hal/src/main/native/include/hal/AddressableLEDTypes.h b/hal/src/main/native/include/hal/AddressableLEDTypes.h
index bdcd742..dbaa776 100644
--- a/hal/src/main/native/include/hal/AddressableLEDTypes.h
+++ b/hal/src/main/native/include/hal/AddressableLEDTypes.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
diff --git a/hal/src/main/native/include/hal/AnalogAccumulator.h b/hal/src/main/native/include/hal/AnalogAccumulator.h
index 9e49e90..c0c928d 100644
--- a/hal/src/main/native/include/hal/AnalogAccumulator.h
+++ b/hal/src/main/native/include/hal/AnalogAccumulator.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
 
@@ -24,7 +21,8 @@
 /**
  * Is the channel attached to an accumulator.
  *
- * @param analogPortHandle Handle to the analog port.
+ * @param[in] analogPortHandle Handle to the analog port.
+ * @param[out] status Error status variable. 0 on success.
  * @return The analog channel is attached to an accumulator.
  */
 HAL_Bool HAL_IsAccumulatorChannel(HAL_AnalogInputHandle analogPortHandle,
@@ -33,7 +31,8 @@
 /**
  * Initialize the accumulator.
  *
- * @param analogPortHandle Handle to the analog port.
+ * @param[in] analogPortHandle Handle to the analog port.
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_InitAccumulator(HAL_AnalogInputHandle analogPortHandle,
                          int32_t* status);
@@ -41,7 +40,8 @@
 /**
  * Resets the accumulator to the initial value.
  *
- * @param analogPortHandle Handle to the analog port.
+ * @param[in] analogPortHandle Handle to the analog port.
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_ResetAccumulator(HAL_AnalogInputHandle analogPortHandle,
                           int32_t* status);
@@ -58,8 +58,9 @@
  * source from channel 1. Because of this, any non-zero oversample bits will
  * affect the size of the value for this field.
  *
- * @param analogPortHandle Handle to the analog port.
- * @param center The center value of the accumulator.
+ * @param[in] analogPortHandle Handle to the analog port.
+ * @param[in] center The center value of the accumulator.
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_SetAccumulatorCenter(HAL_AnalogInputHandle analogPortHandle,
                               int32_t center, int32_t* status);
@@ -67,8 +68,9 @@
 /**
  * Set the accumulator's deadband.
  *
- * @param analogPortHandle Handle to the analog port.
- * @param deadband The deadband of the accumulator.
+ * @param[in] analogPortHandle Handle to the analog port.
+ * @param[in] deadband The deadband of the accumulator.
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_SetAccumulatorDeadband(HAL_AnalogInputHandle analogPortHandle,
                                 int32_t deadband, int32_t* status);
@@ -79,7 +81,8 @@
  * Read the value that has been accumulating on channel 1.
  * The accumulator is attached after the oversample and average engine.
  *
- * @param analogPortHandle Handle to the analog port.
+ * @param[in] analogPortHandle Handle to the analog port.
+ * @param[out] status Error status variable. 0 on success.
  * @return The 64-bit value accumulated since the last Reset().
  */
 int64_t HAL_GetAccumulatorValue(HAL_AnalogInputHandle analogPortHandle,
@@ -91,7 +94,8 @@
  * Read the count of the accumulated values since the accumulator was last
  * Reset().
  *
- * @param analogPortHandle Handle to the analog port.
+ * @param[in] analogPortHandle Handle to the analog port.
+ * @param[out] status Error status variable. 0 on success.
  * @return The number of times samples from the channel were accumulated.
  */
 int64_t HAL_GetAccumulatorCount(HAL_AnalogInputHandle analogPortHandle,
@@ -103,9 +107,10 @@
  * This function reads the value and count from the FPGA atomically.
  * This can be used for averaging.
  *
- * @param analogPortHandle Handle to the analog port.
- * @param value Pointer to the 64-bit accumulated output.
- * @param count Pointer to the number of accumulation cycles.
+ * @param[in] analogPortHandle Handle to the analog port.
+ * @param[in] value Pointer to the 64-bit accumulated output.
+ * @param[in] count Pointer to the number of accumulation cycles.
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_GetAccumulatorOutput(HAL_AnalogInputHandle analogPortHandle,
                               int64_t* value, int64_t* count, int32_t* status);
diff --git a/hal/src/main/native/include/hal/AnalogGyro.h b/hal/src/main/native/include/hal/AnalogGyro.h
index 54030bd..6e5a9c2 100644
--- a/hal/src/main/native/include/hal/AnalogGyro.h
+++ b/hal/src/main/native/include/hal/AnalogGyro.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
 
@@ -24,17 +21,22 @@
 /**
  * Initializes an analog gyro.
  *
- * @param handle handle to the analog port
- * @return       the initialized gyro handle
+ * @param[in] handle handle to the analog port
+ * @param[in] allocationLocation the location where the allocation is occuring
+ *                                (can be null)
+ * @param[out] status the error code, or 0 for success
+ * @return the initialized gyro handle
  */
 HAL_GyroHandle HAL_InitializeAnalogGyro(HAL_AnalogInputHandle handle,
+                                        const char* allocationLocation,
                                         int32_t* status);
 
 /**
  * Sets up an analog gyro with the proper offsets and settings for the KOP
  * analog gyro.
  *
- * @param handle the gyro handle
+ * @param[in] handle the gyro handle
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetupAnalogGyro(HAL_GyroHandle handle, int32_t* status);
 
@@ -51,10 +53,11 @@
  * This is meant to be used if you want to reuse the values from a previous
  * calibration.
  *
- * @param handle                  the gyro handle
- * @param voltsPerDegreePerSecond the gyro volts scaling
- * @param offset                  the gyro offset
- * @param center                  the gyro center
+ * @param[in] handle                  the gyro handle
+ * @param[in] voltsPerDegreePerSecond the gyro volts scaling
+ * @param[in] offset                  the gyro offset
+ * @param[in] center                  the gyro center
+ * @param[out] status                  the error code, or 0 for success
  */
 void HAL_SetAnalogGyroParameters(HAL_GyroHandle handle,
                                  double voltsPerDegreePerSecond, double offset,
@@ -63,8 +66,9 @@
 /**
  * Sets the analog gyro volts per degrees per second scaling.
  *
- * @param handle                  the gyro handle
- * @param voltsPerDegreePerSecond the gyro volts scaling
+ * @param[in] handle                  the gyro handle
+ * @param[in] voltsPerDegreePerSecond the gyro volts scaling
+ * @param[out] status                  the error code, or 0 for success
  */
 void HAL_SetAnalogGyroVoltsPerDegreePerSecond(HAL_GyroHandle handle,
                                               double voltsPerDegreePerSecond,
@@ -73,7 +77,8 @@
 /**
  * Resets the analog gyro value to 0.
  *
- * @param handle the gyro handle
+ * @param[in] handle the gyro handle
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_ResetAnalogGyro(HAL_GyroHandle handle, int32_t* status);
 
@@ -84,15 +89,17 @@
  * setting that as the center. Note that this call blocks for 5 seconds to
  * perform this.
  *
- * @param handle the gyro handle
+ * @param[in] handle the gyro handle
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status);
 
 /**
  * Sets the deadband of the analog gyro.
  *
- * @param handle the gyro handle
- * @param volts  the voltage deadband
+ * @param[in] handle the gyro handle
+ * @param[in] volts  the voltage deadband
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_SetAnalogGyroDeadband(HAL_GyroHandle handle, double volts,
                                int32_t* status);
@@ -100,7 +107,8 @@
 /**
  * Gets the gyro angle in degrees.
  *
- * @param handle the gyro handle
+ * @param[in] handle the gyro handle
+ * @param[out] status Error status variable. 0 on success.
  * @return the gyro angle in degrees
  */
 double HAL_GetAnalogGyroAngle(HAL_GyroHandle handle, int32_t* status);
@@ -108,7 +116,8 @@
 /**
  * Gets the gyro rate in degrees/second.
  *
- * @param handle the gyro handle
+ * @param[in] handle the gyro handle
+ * @param[out] status Error status variable. 0 on success.
  * @return the gyro rate in degrees/second
  */
 double HAL_GetAnalogGyroRate(HAL_GyroHandle handle, int32_t* status);
@@ -118,7 +127,8 @@
  *
  * Can be used to not repeat a calibration but reconstruct the gyro object.
  *
- * @param handle the gyro handle
+ * @param[in] handle the gyro handle
+ * @param[out] status Error status variable. 0 on success.
  * @return the gryo offset
  */
 double HAL_GetAnalogGyroOffset(HAL_GyroHandle handle, int32_t* status);
@@ -128,7 +138,8 @@
  *
  * Can be used to not repeat a calibration but reconstruct the gyro object.
  *
- * @param handle the gyro handle
+ * @param[in] handle the gyro handle
+ * @param[out] status Error status variable. 0 on success.
  * @return the gyro center
  */
 int32_t HAL_GetAnalogGyroCenter(HAL_GyroHandle handle, int32_t* status);
diff --git a/hal/src/main/native/include/hal/AnalogInput.h b/hal/src/main/native/include/hal/AnalogInput.h
index 95ba4e0..956cd21 100644
--- a/hal/src/main/native/include/hal/AnalogInput.h
+++ b/hal/src/main/native/include/hal/AnalogInput.h
@@ -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.
 
 #pragma once
 
@@ -24,11 +21,14 @@
 /**
  * Initializes the analog input port using the given port object.
  *
- * @param portHandle Handle to the port to initialize.
- * @return           the created analog input handle
+ * @param[in] portHandle Handle to the port to initialize.
+ * @param[in] allocationLocation the location where the allocation is occuring
+ *                               (can be null)
+ * @param[out] status the error code, or 0 for success
+ * @return the created analog input handle
  */
-HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(HAL_PortHandle portHandle,
-                                                    int32_t* status);
+HAL_AnalogInputHandle HAL_InitializeAnalogInputPort(
+    HAL_PortHandle portHandle, const char* allocationLocation, int32_t* status);
 
 /**
  * Frees an analog input port.
@@ -69,7 +69,8 @@
  *
  * This is a global setting for the Athena and effects all channels.
  *
- * @param samplesPerSecond The number of samples per channel per second.
+ * @param[in] samplesPerSecond The number of samples per channel per second.
+ * @param[out] status          the error code, or 0 for success
  */
 void HAL_SetAnalogSampleRate(double samplesPerSecond, int32_t* status);
 
@@ -79,6 +80,7 @@
  * This assumes one entry in the scan list.
  * This is a global setting for the Athena and effects all channels.
  *
+ * @param[out] status the error code, or 0 for success
  * @return Sample rate.
  */
 double HAL_GetAnalogSampleRate(int32_t* status);
@@ -90,8 +92,9 @@
  * is 2**bits. Use averaging to improve the stability of your measurement at the
  * expense of sampling rate. The averaging is done automatically in the FPGA.
  *
- * @param analogPortHandle Handle to the analog port to configure.
- * @param bits Number of bits to average.
+ * @param[in] analogPortHandle Handle to the analog port to configure.
+ * @param[in] bits Number of bits to average.
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
                               int32_t bits, int32_t* status);
@@ -102,7 +105,8 @@
  * This gets the number of averaging bits from the FPGA. The actual number of
  * averaged samples is 2**bits. The averaging is done automatically in the FPGA.
  *
- * @param analogPortHandle Handle to the analog port to use.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[out] status the error code, or 0 for success
  * @return Bits to average.
  */
 int32_t HAL_GetAnalogAverageBits(HAL_AnalogInputHandle analogPortHandle,
@@ -116,8 +120,9 @@
  * measurements at the expense of sampling rate. The oversampling is done
  * automatically in the FPGA.
  *
- * @param analogPortHandle Handle to the analog port to use.
- * @param bits Number of bits to oversample.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[in] bits Number of bits to oversample.
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
                                  int32_t bits, int32_t* status);
@@ -129,7 +134,8 @@
  * oversampled values is 2**bits. The oversampling is done automatically in the
  * FPGA.
  *
- * @param analogPortHandle Handle to the analog port to use.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[out] status          the error code, or 0 for success
  * @return Bits to oversample.
  */
 int32_t HAL_GetAnalogOversampleBits(HAL_AnalogInputHandle analogPortHandle,
@@ -142,7 +148,8 @@
  * converter in the module. The units are in A/D converter codes.  Use
  * GetVoltage() to get the analog value in calibrated units.
  *
- * @param analogPortHandle Handle to the analog port to use.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[out] status the error code, or 0 for success
  * @return A sample straight from the channel on this module.
  */
 int32_t HAL_GetAnalogValue(HAL_AnalogInputHandle analogPortHandle,
@@ -159,7 +166,8 @@
  * the module on this channel. Use GetAverageVoltage() to get the analog value
  * in calibrated units.
  *
- * @param analogPortHandle Handle to the analog port to use.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[out] status the error code, or 0 for success
  * @return A sample from the oversample and average engine for the channel.
  */
 int32_t HAL_GetAnalogAverageValue(HAL_AnalogInputHandle analogPortHandle,
@@ -173,8 +181,9 @@
  *
  * @todo This assumes raw values.  Oversampling not supported as is.
  *
- * @param analogPortHandle Handle to the analog port to use.
- * @param voltage The voltage to convert.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[in] voltage The voltage to convert.
+ * @param[out] status the error code, or 0 for success
  * @return The raw value for the channel.
  */
 int32_t HAL_GetAnalogVoltsToValue(HAL_AnalogInputHandle analogPortHandle,
@@ -186,7 +195,8 @@
  * The value is scaled to units of Volts using the calibrated scaling data from
  * GetLSBWeight() and GetOffset().
  *
- * @param analogPortHandle Handle to the analog port to use.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[out] status the error code, or 0 for success
  * @return A scaled sample straight from the channel on this module.
  */
 double HAL_GetAnalogVoltage(HAL_AnalogInputHandle analogPortHandle,
@@ -201,7 +211,8 @@
  * be higher resolution, but it will update more slowly. Using averaging will
  * cause this value to be more stable, but it will update more slowly.
  *
- * @param analogPortHandle Handle to the analog port to use.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[out] status the error code, or 0 for success
  * @return A scaled sample from the output of the oversample and average engine
  * for the channel.
  */
@@ -215,7 +226,8 @@
  *
  * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
  *
- * @param analogPortHandle Handle to the analog port to use.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[out] status the error code, or 0 for success
  * @return Least significant bit weight.
  */
 int32_t HAL_GetAnalogLSBWeight(HAL_AnalogInputHandle analogPortHandle,
@@ -228,7 +240,8 @@
  *
  * Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
  *
- * @param analogPortHandle Handle to the analog port to use.
+ * @param[in] analogPortHandle Handle to the analog port to use.
+ * @param[out] status Error status variable. 0 on success.
  * @return Offset constant.
  */
 int32_t HAL_GetAnalogOffset(HAL_AnalogInputHandle analogPortHandle,
@@ -237,9 +250,11 @@
 /**
  *  Get the analog voltage from a raw value.
  *
- * @param analogPortHandle  Handle to the analog port the values were read from.
- * @param rawValue          The raw analog value
- * @return                  The voltage relating to the value
+ * @param[in] analogPortHandle  Handle to the analog port the values were read
+ *                              from.
+ * @param[in] rawValue          The raw analog value
+ * @param[out] status           Error status variable. 0 on success.
+ * @return The voltage relating to the value
  */
 double HAL_GetAnalogValueToVolts(HAL_AnalogInputHandle analogPortHandle,
                                  int32_t rawValue, int32_t* status);
diff --git a/hal/src/main/native/include/hal/AnalogOutput.h b/hal/src/main/native/include/hal/AnalogOutput.h
index ba0d93b..26e5231 100644
--- a/hal/src/main/native/include/hal/AnalogOutput.h
+++ b/hal/src/main/native/include/hal/AnalogOutput.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
 
@@ -24,11 +21,14 @@
 /**
  * Initializes the analog output port using the given port object.
  *
- * @param handle handle to the port
- * @return       the created analog output handle
+ * @param[in] portHandle handle to the port
+ * @param[in] allocationLocation the location where the allocation is occuring
+ *                               (can be null)
+ * @param[out] status Error status variable. 0 on success.
+ * @return the created analog output handle
  */
-HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(HAL_PortHandle portHandle,
-                                                      int32_t* status);
+HAL_AnalogOutputHandle HAL_InitializeAnalogOutputPort(
+    HAL_PortHandle portHandle, const char* allocationLocation, int32_t* status);
 
 /**
  * Frees an analog output port.
@@ -40,8 +40,9 @@
 /**
  * Sets an analog output value.
  *
- * @param analogOutputHandle the analog output handle
- * @param voltage            the voltage (0-5v) to output
+ * @param[in] analogOutputHandle the analog output handle
+ * @param[in] voltage            the voltage (0-5v) to output
+ * @param[out] status            Error status variable. 0 on success.
  */
 void HAL_SetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
                          double voltage, int32_t* status);
@@ -49,8 +50,9 @@
 /**
  * Gets the current analog output value.
  *
- * @param analogOutputHandle the analog output handle
- * @return                   the current output voltage (0-5v)
+ * @param[in] analogOutputHandle the analog output handle
+ * @param[out] status            Error status variable. 0 on success.
+ * @return the current output voltage (0-5v)
  */
 double HAL_GetAnalogOutput(HAL_AnalogOutputHandle analogOutputHandle,
                            int32_t* status);
diff --git a/hal/src/main/native/include/hal/AnalogTrigger.h b/hal/src/main/native/include/hal/AnalogTrigger.h
index 85d7680..72727a8 100644
--- a/hal/src/main/native/include/hal/AnalogTrigger.h
+++ b/hal/src/main/native/include/hal/AnalogTrigger.h
@@ -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.
 
 #pragma once
 
@@ -36,8 +33,9 @@
 /**
  * Initializes an analog trigger.
  *
- * @param portHandle the analog input to use for triggering
- * @return           the created analog trigger handle
+ * @param[in] portHandle the analog input to use for triggering
+ * @param[out] status     Error status variable. 0 on success.
+ * @return the created analog trigger handle
  */
 HAL_AnalogTriggerHandle HAL_InitializeAnalogTrigger(
     HAL_AnalogInputHandle portHandle, int32_t* status);
@@ -45,6 +43,8 @@
 /**
  * Initializes an analog trigger with a Duty Cycle input
  *
+ * @param[in] dutyCycleHandle the analog input to use for duty cycle
+ * @param[out] status          Error status variable. 0 on success.
  */
 HAL_AnalogTriggerHandle HAL_InitializeAnalogTriggerDutyCycle(
     HAL_DutyCycleHandle dutyCycleHandle, int32_t* status);
@@ -52,7 +52,8 @@
 /**
  * Frees an analog trigger.
  *
- * @param analogTriggerHandle the trigger handle
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_CleanAnalogTrigger(HAL_AnalogTriggerHandle analogTriggerHandle,
                             int32_t* status);
@@ -63,9 +64,10 @@
  * HAL_SetAnalogTriggerLimitsVoltage or HAL_SetAnalogTriggerLimitsDutyCycle
  * is likely better in most cases.
  *
- * @param analogTriggerHandle the trigger handle
- * @param lower               the lower ADC value
- * @param upper               the upper ADC value
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[in] lower               the lower ADC value
+ * @param[in] upper               the upper ADC value
+ * @param[out] status              Error status variable. 0 on success.
  */
 void HAL_SetAnalogTriggerLimitsRaw(HAL_AnalogTriggerHandle analogTriggerHandle,
                                    int32_t lower, int32_t upper,
@@ -76,14 +78,25 @@
  *
  * The limits are given as floating point voltage values.
  *
- * @param analogTriggerHandle the trigger handle
- * @param lower               the lower voltage value
- * @param upper               the upper voltage value
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[in] lower               the lower voltage value
+ * @param[in] upper               the upper voltage value
+ * @param[out] status              Error status variable. 0 on success.
  */
 void HAL_SetAnalogTriggerLimitsVoltage(
     HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
     int32_t* status);
 
+/**
+ * Sets the upper and lower limits of the analog trigger.
+ *
+ * The limits are given as floating point duty cycle values.
+ *
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[in] lower               the lower duty cycle value
+ * @param[in] upper               the upper duty cycle value
+ * @param[out] status              Error status variable. 0 on success.
+ */
 void HAL_SetAnalogTriggerLimitsDutyCycle(
     HAL_AnalogTriggerHandle analogTriggerHandle, double lower, double upper,
     int32_t* status);
@@ -97,8 +110,9 @@
  * This is not allowed to be used if filtered mode is set.
  * This is not allowed to be used with Duty Cycle based inputs.
  *
- * @param analogTriggerHandle the trigger handle
- * @param useAveragedValue    true to use averaged values, false for raw
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[in] useAveragedValue    true to use averaged values, false for raw
+ * @param[out] status              Error status variable. 0 on success.
  */
 void HAL_SetAnalogTriggerAveraged(HAL_AnalogTriggerHandle analogTriggerHandle,
                                   HAL_Bool useAveragedValue, int32_t* status);
@@ -112,9 +126,10 @@
  *
  * This is not allowed to be used if averaged mode is set.
  *
- * @param analogTriggerHandle the trigger handle
- * @param useFilteredValue    true to use filtered values, false for average or
- * raw
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[in] useFilteredValue    true to use filtered values, false for average
+ *                                or raw
+ * @param[out] status             Error status variable. 0 on success.
  */
 void HAL_SetAnalogTriggerFiltered(HAL_AnalogTriggerHandle analogTriggerHandle,
                                   HAL_Bool useFilteredValue, int32_t* status);
@@ -124,8 +139,9 @@
  *
  * True if the analog input is between the upper and lower limits.
  *
- * @param analogTriggerHandle the trigger handle
- * @return                    the InWindow output of the analog trigger
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the InWindow output of the analog trigger
  */
 HAL_Bool HAL_GetAnalogTriggerInWindow(
     HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status);
@@ -137,8 +153,9 @@
  * False if below lower limit.
  * If in Hysteresis, maintain previous state.
  *
- * @param analogTriggerHandle the trigger handle
- * @return                    the TriggerState output of the analog trigger
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[out] status              Error status variable. 0 on success.
+ * @return the TriggerState output of the analog trigger
  */
 HAL_Bool HAL_GetAnalogTriggerTriggerState(
     HAL_AnalogTriggerHandle analogTriggerHandle, int32_t* status);
@@ -146,9 +163,10 @@
 /**
  * Gets the state of the analog trigger output.
  *
- * @param analogTriggerHandle the trigger handle
- * @param type                the type of trigger to trigger on
- * @return                    the state of the analog trigger output
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[in] type                the type of trigger to trigger on
+ * @param[out] status              Error status variable. 0 on success.
+ * @return the state of the analog trigger output
  */
 HAL_Bool HAL_GetAnalogTriggerOutput(HAL_AnalogTriggerHandle analogTriggerHandle,
                                     HAL_AnalogTriggerType type,
@@ -157,7 +175,8 @@
 /**
  * Get the FPGA index for the AnlogTrigger.
  *
- * @param analogTriggerHandle the trigger handle
+ * @param[in] analogTriggerHandle the trigger handle
+ * @param[out] status              Error status variable. 0 on success.
  * @return the FPGA index
  */
 int32_t HAL_GetAnalogTriggerFPGAIndex(
diff --git a/hal/src/main/native/include/hal/CAN.h b/hal/src/main/native/include/hal/CAN.h
index 4f91bc1..77a6239 100644
--- a/hal/src/main/native/include/hal/CAN.h
+++ b/hal/src/main/native/include/hal/CAN.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
 
@@ -48,11 +45,12 @@
 /**
  * Sends a CAN message.
  *
- * @param messageID the CAN ID to send
- * @param data      the data to send (0-8 bytes)
- * @param dataSize  the size of the data to send (0-8 bytes)
- * @param periodMs  the period to repeat the packet at. Use
- * HAL_CAN_SEND_PERIOD_NO_REPEAT to not repeat.
+ * @param[in] messageID the CAN ID to send
+ * @param[in] data      the data to send (0-8 bytes)
+ * @param[in] dataSize  the size of the data to send (0-8 bytes)
+ * @param[in] periodMs  the period to repeat the packet at. Use
+ *                       HAL_CAN_SEND_PERIOD_NO_REPEAT to not repeat.
+ * @param[out] status    Error status variable. 0 on success.
  */
 void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
                          uint8_t dataSize, int32_t periodMs, int32_t* status);
@@ -60,12 +58,13 @@
 /**
  * Receives a CAN message.
  *
- * @param messageID     store for the received message ID
- * @param messageIDMask the message ID mask to look for
- * @param data          data output (8 bytes)
- * @param dataSize      data length (0-8 bytes)
- * @param timeStamp     the packet received timestamp (based off of
- * CLOCK_MONOTONIC)
+ * @param[out] messageID     store for the received message ID
+ * @param[in] messageIDMask the message ID mask to look for
+ * @param[out] data          data output (8 bytes)
+ * @param[out] dataSize      data length (0-8 bytes)
+ * @param[out] timeStamp     the packet received timestamp (based off of
+ *                           CLOCK_MONOTONIC)
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
                             uint8_t* data, uint8_t* dataSize,
@@ -74,10 +73,11 @@
 /**
  * Opens a CAN stream.
  *
- * @param sessionHandle output for the session handle
- * @param messageID     the message ID to read
- * @param messageIDMask the mssage ID mask
- * @param maxMessages   the maximum number of messages to stream
+ * @param[out] sessionHandle output for the session handle
+ * @param[in] messageID     the message ID to read
+ * @param[in] messageIDMask the mssage ID mask
+ * @param[in] maxMessages   the maximum number of messages to stream
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_CAN_OpenStreamSession(uint32_t* sessionHandle, uint32_t messageID,
                                uint32_t messageIDMask, uint32_t maxMessages,
@@ -93,10 +93,11 @@
 /**
  * Reads a CAN stream message.
  *
- * @param sessionHandle  the session handle
- * @param messages       array of messages
- * @param messagesToRead the max number of messages to read
- * @param messageRead    the number of messages actually read
+ * @param[in] sessionHandle  the session handle
+ * @param[in] messages       array of messages
+ * @param[in] messagesToRead the max number of messages to read
+ * @param[out] messagesRead   the number of messages actually read
+ * @param[out] status         Error status variable. 0 on success.
  */
 void HAL_CAN_ReadStreamSession(uint32_t sessionHandle,
                                struct HAL_CANStreamMessage* messages,
@@ -106,11 +107,12 @@
 /**
  * Gets CAN status information.
  *
- * @param percentBusUtilization the bus utilization
- * @param busOffCount           the number of bus off errors
- * @param txFullCount           the number of tx full errors
- * @param receiveErrorCount     the number of receive errors
- * @param transmitErrorCount    the number of transmit errors
+ * @param[out] percentBusUtilization the bus utilization
+ * @param[out] busOffCount           the number of bus off errors
+ * @param[out] txFullCount           the number of tx full errors
+ * @param[out] receiveErrorCount     the number of receive errors
+ * @param[out] transmitErrorCount    the number of transmit errors
+ * @param[out] status                Error status variable. 0 on success.
  */
 void HAL_CAN_GetCANStatus(float* percentBusUtilization, uint32_t* busOffCount,
                           uint32_t* txFullCount, uint32_t* receiveErrorCount,
diff --git a/hal/src/main/native/include/hal/CANAPI.h b/hal/src/main/native/include/hal/CANAPI.h
index 7a6bd88..29859cf 100644
--- a/hal/src/main/native/include/hal/CANAPI.h
+++ b/hal/src/main/native/include/hal/CANAPI.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -27,10 +24,11 @@
  *
  * These follow the FIRST standard CAN layout. Link TBD
  *
- * @param manufacturer the can manufacturer
- * @param deviceId     the device ID (0-63)
- * @param deviceType   the device type
- * @return             the created CAN handle
+ * @param[in] manufacturer the can manufacturer
+ * @param[in] deviceId     the device ID (0-63)
+ * @param[in] deviceType   the device type
+ * @param[out] status      Error status variable. 0 on success.
+ * @return the created CAN handle
  */
 HAL_CANHandle HAL_InitializeCAN(HAL_CANManufacturer manufacturer,
                                 int32_t deviceId, HAL_CANDeviceType deviceType,
@@ -48,10 +46,11 @@
  *
  * This ID is 10 bits.
  *
- * @param handle the CAN handle
- * @param data   the data to write (0-8 bytes)
- * @param length the length of data (0-8)
- * @param apiId  the ID to write (0-1023 bits)
+ * @param[in] handle  the CAN handle
+ * @param[in] data    the data to write (0-8 bytes)
+ * @param[in] length  the length of data (0-8)
+ * @param[in] apiId   the ID to write (0-1023 bits)
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_WriteCANPacket(HAL_CANHandle handle, const uint8_t* data,
                         int32_t length, int32_t apiId, int32_t* status);
@@ -63,11 +62,12 @@
  *
  * The RoboRIO will automatically repeat the packet at the specified interval
  *
- * @param handle   the CAN handle
- * @param data     the data to write (0-8 bytes)
- * @param length   the length of data (0-8)
- * @param apiId    the ID to write (0-1023)
- * @param repeatMs the period to repeat in ms
+ * @param[in] handle   the CAN handle
+ * @param[in] data     the data to write (0-8 bytes)
+ * @param[in] length   the length of data (0-8)
+ * @param[in] apiId    the ID to write (0-1023)
+ * @param[in] repeatMs the period to repeat in ms
+ * @param[out] status  Error status variable. 0 on success.
  */
 void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data,
                                  int32_t length, int32_t apiId,
@@ -80,9 +80,10 @@
  * By spec, the length must be equal to the length sent by the other device,
  * otherwise behavior is unspecified.
  *
- * @param handle   the CAN handle
- * @param length   the length of data to request (0-8)
- * @param apiId    the ID to write (0-1023)
+ * @param[in] handle   the CAN handle
+ * @param[in] length   the length of data to request (0-8)
+ * @param[in] apiId    the ID to write (0-1023)
+ * @param[out] status  Error status variable. 0 on success.
  */
 void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId,
                           int32_t* status);
@@ -92,8 +93,9 @@
  *
  * This ID is 10 bits.
  *
- * @param handle the CAN handle
- * @param apiId  the ID to stop repeating (0-1023)
+ * @param[in] handle  the CAN handle
+ * @param[in] apiId   the ID to stop repeating (0-1023)
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId,
                                 int32_t* status);
@@ -104,12 +106,13 @@
  * This will only return properly once per packet received. Multiple calls
  * without receiving another packet will return an error code.
  *
- * @param handle            the CAN handle
- * @param apiId             the ID to read (0-1023)
- * @param data              the packet data (8 bytes)
- * @param length            the received length (0-8 bytes)
- * @param receivedTimestamp the packet received timestamp (based off of
- * CLOCK_MONOTONIC)
+ * @param[in] handle             the CAN handle
+ * @param[in] apiId              the ID to read (0-1023)
+ * @param[out] data              the packet data (8 bytes)
+ * @param[out] length            the received length (0-8 bytes)
+ * @param[out] receivedTimestamp the packet received timestamp (based off of
+ *                               CLOCK_MONOTONIC)
+ * @param[out] status            Error status variable. 0 on success.
  */
 void HAL_ReadCANPacketNew(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
                           int32_t* length, uint64_t* receivedTimestamp,
@@ -119,12 +122,13 @@
  * Reads a CAN packet. The will continuously return the last packet received,
  * without accounting for packet age.
  *
- * @param handle            the CAN handle
- * @param apiId             the ID to read (0-1023)
- * @param data              the packet data (8 bytes)
- * @param length            the received length (0-8 bytes)
- * @param receivedTimestamp the packet received timestamp (based off of
- * CLOCK_MONOTONIC)
+ * @param[in] handle             the CAN handle
+ * @param[in] apiId              the ID to read (0-1023)
+ * @param[out] data              the packet data (8 bytes)
+ * @param[out] length            the received length (0-8 bytes)
+ * @param[out] receivedTimestamp the packet received timestamp (based off of
+ *                               CLOCK_MONOTONIC)
+ * @param[out] status            Error status variable. 0 on success.
  */
 void HAL_ReadCANPacketLatest(HAL_CANHandle handle, int32_t apiId, uint8_t* data,
                              int32_t* length, uint64_t* receivedTimestamp,
@@ -135,13 +139,14 @@
  * packet is older then the requested timeout. Then it will return an error
  * code.
  *
- * @param handle            the CAN handle
- * @param apiId             the ID to read (0-1023)
- * @param data              the packet data (8 bytes)
- * @param length            the received length (0-8 bytes)
- * @param receivedTimestamp the packet received timestamp (based off of
- * CLOCK_MONOTONIC)
- * @param timeoutMs         the timeout time for the packet
+ * @param[in] handle             the CAN handle
+ * @param[in] apiId              the ID to read (0-1023)
+ * @param[out] data              the packet data (8 bytes)
+ * @param[out] length            the received length (0-8 bytes)
+ * @param[out] receivedTimestamp the packet received timestamp (based off of
+ *                               CLOCK_MONOTONIC)
+ * @param[out] timeoutMs         the timeout time for the packet
+ * @param[out] status            Error status variable. 0 on success.
  */
 void HAL_ReadCANPacketTimeout(HAL_CANHandle handle, int32_t apiId,
                               uint8_t* data, int32_t* length,
diff --git a/hal/src/main/native/include/hal/CANAPITypes.h b/hal/src/main/native/include/hal/CANAPITypes.h
index 5155d93..1be672e 100644
--- a/hal/src/main/native/include/hal/CANAPITypes.h
+++ b/hal/src/main/native/include/hal/CANAPITypes.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
diff --git a/hal/src/main/native/include/hal/CTREPCM.h b/hal/src/main/native/include/hal/CTREPCM.h
new file mode 100644
index 0000000..1bed928
--- /dev/null
+++ b/hal/src/main/native/include/hal/CTREPCM.h
@@ -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.
+
+#pragma once
+
+#include <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_ctre_pcm CTRE PCM Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HAL_CTREPCMHandle HAL_InitializeCTREPCM(int32_t module,
+                                        const char* allocationLocation,
+                                        int32_t* status);
+void HAL_FreeCTREPCM(HAL_CTREPCMHandle handle);
+
+HAL_Bool HAL_CheckCTREPCMSolenoidChannel(int32_t channel);
+
+HAL_Bool HAL_GetCTREPCMCompressor(HAL_CTREPCMHandle handle, int32_t* status);
+void HAL_SetCTREPCMClosedLoopControl(HAL_CTREPCMHandle handle, HAL_Bool enabled,
+                                     int32_t* status);
+HAL_Bool HAL_GetCTREPCMClosedLoopControl(HAL_CTREPCMHandle handle,
+                                         int32_t* status);
+HAL_Bool HAL_GetCTREPCMPressureSwitch(HAL_CTREPCMHandle handle,
+                                      int32_t* status);
+double HAL_GetCTREPCMCompressorCurrent(HAL_CTREPCMHandle handle,
+                                       int32_t* status);
+
+HAL_Bool HAL_GetCTREPCMCompressorCurrentTooHighFault(HAL_CTREPCMHandle handle,
+                                                     int32_t* status);
+HAL_Bool HAL_GetCTREPCMCompressorCurrentTooHighStickyFault(
+    HAL_CTREPCMHandle handle, int32_t* status);
+HAL_Bool HAL_GetCTREPCMCompressorShortedStickyFault(HAL_CTREPCMHandle handle,
+                                                    int32_t* status);
+HAL_Bool HAL_GetCTREPCMCompressorShortedFault(HAL_CTREPCMHandle handle,
+                                              int32_t* status);
+HAL_Bool HAL_GetCTREPCMCompressorNotConnectedStickyFault(
+    HAL_CTREPCMHandle handle, int32_t* status);
+HAL_Bool HAL_GetCTREPCMCompressorNotConnectedFault(HAL_CTREPCMHandle handle,
+                                                   int32_t* status);
+
+int32_t HAL_GetCTREPCMSolenoids(HAL_CTREPCMHandle handle, int32_t* status);
+void HAL_SetCTREPCMSolenoids(HAL_CTREPCMHandle handle, int32_t mask,
+                             int32_t values, int32_t* status);
+
+int32_t HAL_GetCTREPCMSolenoidDisabledList(HAL_CTREPCMHandle handle,
+                                           int32_t* status);
+HAL_Bool HAL_GetCTREPCMSolenoidVoltageStickyFault(HAL_CTREPCMHandle handle,
+                                                  int32_t* status);
+HAL_Bool HAL_GetCTREPCMSolenoidVoltageFault(HAL_CTREPCMHandle handle,
+                                            int32_t* status);
+
+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);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/ChipObject.h b/hal/src/main/native/include/hal/ChipObject.h
index d891ced..4526a1a 100644
--- a/hal/src/main/native/include/hal/ChipObject.h
+++ b/hal/src/main/native/include/hal/ChipObject.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 #pragma GCC diagnostic push
diff --git a/hal/src/main/native/include/hal/Compressor.h b/hal/src/main/native/include/hal/Compressor.h
deleted file mode 100644
index cb58e46..0000000
--- a/hal/src/main/native/include/hal/Compressor.h
+++ /dev/null
@@ -1,143 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <stdint.h>
-
-#include "hal/Types.h"
-
-/**
- * @defgroup hal_compressor Compressor Functions
- * @ingroup hal_capi
- * @{
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Initializes a compressor on the given PCM module.
- *
- * @param module the module number
- * @return       the created handle
- */
-HAL_CompressorHandle HAL_InitializeCompressor(int32_t module, int32_t* status);
-
-/**
- * Gets if a compressor module is valid.
- *
- * @param module the module number
- * @return       true if the module is valid, otherwise false
- */
-HAL_Bool HAL_CheckCompressorModule(int32_t module);
-
-/**
- * Gets the compressor state (on or off).
- *
- * @param compressorHandle the compressor handle
- * @return                 true if the compressor is on, otherwise false
- */
-HAL_Bool HAL_GetCompressor(HAL_CompressorHandle compressorHandle,
-                           int32_t* status);
-
-/**
- * Sets the compressor to closed loop mode.
- *
- * @param compressorHandle the compressor handle
- * @param value            true for closed loop mode, false for off
- */
-void HAL_SetCompressorClosedLoopControl(HAL_CompressorHandle compressorHandle,
-                                        HAL_Bool value, int32_t* status);
-
-/**
- * Gets if the compressor is in closed loop mode.
- *
- * @param compressorHandle the compressor handle
- * @return                 true if the compressor is in closed loop mode,
- * otherwise false
- */
-HAL_Bool HAL_GetCompressorClosedLoopControl(
-    HAL_CompressorHandle compressorHandle, int32_t* status);
-
-/**
- * Gets the compressor pressure switch state.
- *
- * @param compressorHandle the compressor handle
- * @return                 true if the pressure switch is triggered, otherwise
- * false
- */
-HAL_Bool HAL_GetCompressorPressureSwitch(HAL_CompressorHandle compressorHandle,
-                                         int32_t* status);
-
-/**
- * Gets the compressor current.
- *
- * @param compressorHandle the compressor handle
- * @return                 the compressor current in amps
- */
-double HAL_GetCompressorCurrent(HAL_CompressorHandle compressorHandle,
-                                int32_t* status);
-
-/**
- * Gets if the compressor is faulted because of too high of current.
- *
- * @param compressorHandle the compressor handle
- * @return                 true if falted, otherwise false
- */
-HAL_Bool HAL_GetCompressorCurrentTooHighFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status);
-
-/**
- * Gets if a sticky fauly is triggered because of too high of current.
- *
- * @param compressorHandle the compressor handle
- * @return                 true if falted, otherwise false
- */
-HAL_Bool HAL_GetCompressorCurrentTooHighStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status);
-
-/**
- * Gets if a sticky fauly is triggered because of a short.
- *
- * @param compressorHandle the compressor handle
- * @return                 true if falted, otherwise false
- */
-HAL_Bool HAL_GetCompressorShortedStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status);
-
-/**
- * Gets if the compressor is faulted because of a short.
- *
- * @param compressorHandle the compressor handle
- * @return                 true if shorted, otherwise false
- */
-HAL_Bool HAL_GetCompressorShortedFault(HAL_CompressorHandle compressorHandle,
-                                       int32_t* status);
-
-/**
- * Gets if a sticky fault is triggered of the compressor not connected.
- *
- * @param compressorHandle the compressor handle
- * @return                 true if falted, otherwise false
- */
-HAL_Bool HAL_GetCompressorNotConnectedStickyFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status);
-
-/**
- * Gets if the compressor is not connected.
- *
- * @param compressorHandle the compressor handle
- * @return                 true if not connected, otherwise false
- */
-HAL_Bool HAL_GetCompressorNotConnectedFault(
-    HAL_CompressorHandle compressorHandle, int32_t* status);
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-/** @} */
diff --git a/hal/src/main/native/include/hal/Constants.h b/hal/src/main/native/include/hal/Constants.h
index 2a4d409..c8c731c 100644
--- a/hal/src/main/native/include/hal/Constants.h
+++ b/hal/src/main/native/include/hal/Constants.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/include/hal/Counter.h b/hal/src/main/native/include/hal/Counter.h
index c0dd057..cc2d776 100644
--- a/hal/src/main/native/include/hal/Counter.h
+++ b/hal/src/main/native/include/hal/Counter.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
 
@@ -37,9 +34,10 @@
 /**
  * Initializes a counter.
  *
- * @param mode  the counter mode
- * @param index the compressor index (output)
- * @return      the created handle
+ * @param[in] mode    the counter mode
+ * @param[in] index   the compressor index (output)
+ * @param[out] status Error status variable. 0 on success.
+ * @return the created handle
  */
 HAL_CounterHandle HAL_InitializeCounter(HAL_Counter_Mode mode, int32_t* index,
                                         int32_t* status);
@@ -47,15 +45,17 @@
 /**
  * Frees a counter.
  *
- * @param counterHandle the counter handle
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_FreeCounter(HAL_CounterHandle counterHandle, int32_t* status);
 
 /**
  * Sets the average sample size of a counter.
  *
- * @param counterHandle the counter handle
- * @param size          the size of samples to average
+ * @param[in] counterHandle  the counter handle
+ * @param[in] size           the size of samples to average
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_SetCounterAverageSize(HAL_CounterHandle counterHandle, int32_t size,
                                int32_t* status);
@@ -63,11 +63,13 @@
 /**
  * Sets the source object that causes the counter to count up.
  *
- * @param counterHandle       the counter handle
- * @param digitalSourceHandle the digital source handle (either a
- * HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
- * @param analogTriggerType   the analog trigger type if the source is an analog
- * trigger
+ * @param[in] counterHandle       the counter handle
+ * @param[in] digitalSourceHandle the digital source handle (either a
+ *                                HAL_AnalogTriggerHandle or a
+ *                                HAL_DigitalHandle)
+ * @param[in] analogTriggerType   the analog trigger type if the source is an
+ *                                analog trigger
+ * @param[out] status             Error status variable. 0 on success.
  */
 void HAL_SetCounterUpSource(HAL_CounterHandle counterHandle,
                             HAL_Handle digitalSourceHandle,
@@ -79,9 +81,10 @@
  *
  * Note that both are allowed to be set true at the same time without issues.
  *
- * @param counterHandle the counter handle
- * @param risingEdge    true to trigger on rising
- * @param fallingEdge   true to trigger on falling
+ * @param[in] counterHandle  the counter handle
+ * @param[in] risingEdge     true to trigger on rising
+ * @param[in] fallingEdge    true to trigger on falling
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_SetCounterUpSourceEdge(HAL_CounterHandle counterHandle,
                                 HAL_Bool risingEdge, HAL_Bool fallingEdge,
@@ -90,18 +93,21 @@
 /**
  * Disables the up counting source to the counter.
  *
- * @param counterHandle the counter handle
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_ClearCounterUpSource(HAL_CounterHandle counterHandle, int32_t* status);
 
 /**
  * Sets the source object that causes the counter to count down.
  *
- * @param counterHandle       the counter handle
- * @param digitalSourceHandle the digital source handle (either a
- * HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
- * @param analogTriggerType   the analog trigger type if the source is an analog
- * trigger
+ * @param[in] counterHandle       the counter handle
+ * @param[in] digitalSourceHandle the digital source handle (either a
+ *                                HAL_AnalogTriggerHandle or a
+ *                                HAL_DigitalHandle)
+ * @param[in] analogTriggerType   the analog trigger type if the source is an
+ *                                analog trigger
+ * @param[out] status             Error status variable. 0 on success.
  */
 void HAL_SetCounterDownSource(HAL_CounterHandle counterHandle,
                               HAL_Handle digitalSourceHandle,
@@ -112,9 +118,10 @@
  * Sets the down source to either detect rising edges or falling edges.
  * Note that both are allowed to be set true at the same time without issues.
  *
- * @param counterHandle the counter handle
- * @param risingEdge    true to trigger on rising
- * @param fallingEdge   true to trigger on falling
+ * @param[in] counterHandle  the counter handle
+ * @param[in] risingEdge     true to trigger on rising
+ * @param[in] fallingEdge    true to trigger on falling
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_SetCounterDownSourceEdge(HAL_CounterHandle counterHandle,
                                   HAL_Bool risingEdge, HAL_Bool fallingEdge,
@@ -123,7 +130,8 @@
 /**
  * Disables the down counting source to the counter.
  *
- * @param counterHandle the counter handle
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_ClearCounterDownSource(HAL_CounterHandle counterHandle,
                                 int32_t* status);
@@ -133,7 +141,8 @@
  *
  * Up and down counts are sourced independently from two inputs.
  *
- * @param counterHandle the counter handle
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetCounterUpDownMode(HAL_CounterHandle counterHandle, int32_t* status);
 
@@ -143,7 +152,8 @@
  * The direction is determined by the B input, with counting happening with the
  * A input.
  *
- * @param counterHandle the counter handle
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetCounterExternalDirectionMode(HAL_CounterHandle counterHandle,
                                          int32_t* status);
@@ -154,8 +164,10 @@
  * The counter counts up based on the time the input is triggered. High or Low
  * depends on the highSemiPeriod parameter.
  *
- * @param counterHandle  the counter handle
- * @param highSemiPeriod true for counting when the input is high, false for low
+ * @param[in] counterHandle  the counter handle
+ * @param[in] highSemiPeriod true for counting when the input is high, false for
+ *                           low
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_SetCounterSemiPeriodMode(HAL_CounterHandle counterHandle,
                                   HAL_Bool highSemiPeriod, int32_t* status);
@@ -166,9 +178,10 @@
  *
  * This mode is most useful for direction sensitive gear tooth sensors.
  *
- * @param counterHandle the counter handle
- * @param threshold The pulse length beyond which the counter counts the
- * opposite direction (seconds)
+ * @param[in] counterHandle the counter handle
+ * @param[in] threshold     The pulse length beyond which the counter counts the
+ *                          opposite direction (seconds)
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetCounterPulseLengthMode(HAL_CounterHandle counterHandle,
                                    double threshold, int32_t* status);
@@ -178,7 +191,8 @@
  * timer to average when calculating the period. Perform averaging to account
  * for mechanical imperfections or as oversampling to increase resolution.
  *
- * @param counterHandle the counter handle
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
  * @return SamplesToAverage The number of samples being averaged (from 1 to 127)
  */
 int32_t HAL_GetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
@@ -189,8 +203,9 @@
  * timer to average when calculating the period. Perform averaging to account
  * for mechanical imperfections or as oversampling to increase resolution.
  *
- * @param counterHandle    the counter handle
- * @param samplesToAverage The number of samples to average from 1 to 127
+ * @param[in] counterHandle    the counter handle
+ * @param[in] samplesToAverage The number of samples to average from 1 to 127
+ * @param[out] status          Error status variable. 0 on success.
  */
 void HAL_SetCounterSamplesToAverage(HAL_CounterHandle counterHandle,
                                     int32_t samplesToAverage, int32_t* status);
@@ -201,7 +216,8 @@
  * Sets the counter value to zero. This does not effect the running state of the
  * counter, just sets the current value to zero.
  *
- * @param counterHandle the counter handle
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_ResetCounter(HAL_CounterHandle counterHandle, int32_t* status);
 
@@ -211,8 +227,9 @@
  * Reads the value at this instant. It may still be running, so it reflects the
  * current value. Next time it is read, it might have a different value.
  *
- * @param counterHandle the counter handle
- * @return              the current counter value
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the current counter value
  */
 int32_t HAL_GetCounter(HAL_CounterHandle counterHandle, int32_t* status);
 
@@ -222,8 +239,9 @@
  * Returns the time interval of the most recent count. This can be used for
  * velocity calculations to determine shaft speed.
  *
- * @param counterHandle the counter handle
- * @returns             the period of the last two pulses in units of seconds
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the period of the last two pulses in units of seconds
  */
 double HAL_GetCounterPeriod(HAL_CounterHandle counterHandle, int32_t* status);
 
@@ -234,9 +252,10 @@
  * used to determine the "stopped" state of the counter using the
  * HAL_GetCounterStopped method.
  *
- * @param counterHandle the counter handle
- * @param maxPeriod     the maximum period where the counted device is
- * considered moving in seconds
+ * @param[in] counterHandle the counter handle
+ * @param[in] maxPeriod     the maximum period where the counted device is
+ *                          considered moving in seconds
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetCounterMaxPeriod(HAL_CounterHandle counterHandle, double maxPeriod,
                              int32_t* status);
@@ -261,8 +280,9 @@
  * (since it is updated at the end of an average and there are no samples to
  * average).
  *
- * @param counterHandle the counter handle
- * @param enabled       true to enable counter updating with no samples
+ * @param[in] counterHandle the counter handle
+ * @param[in] enabled       true to enable counter updating with no samples
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetCounterUpdateWhenEmpty(HAL_CounterHandle counterHandle,
                                    HAL_Bool enabled, int32_t* status);
@@ -274,9 +294,10 @@
  * using the SetMaxPeriod method. If the clock exceeds the MaxPeriod, then the
  * device (and counter) are assumed to be stopped and it returns true.
  *
- * @param counterHandle the counter handle
- * @return              true if the most recent counter period exceeds the
- * MaxPeriod value set by SetMaxPeriod
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return true if the most recent counter period exceeds the MaxPeriod value
+ *         set by SetMaxPeriod
  */
 HAL_Bool HAL_GetCounterStopped(HAL_CounterHandle counterHandle,
                                int32_t* status);
@@ -284,8 +305,9 @@
 /**
  * Gets the last direction the counter value changed.
  *
- * @param counterHandle the counter handle
- * @return              the last direction the counter value changed
+ * @param[in] counterHandle the counter handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the last direction the counter value changed
  */
 HAL_Bool HAL_GetCounterDirection(HAL_CounterHandle counterHandle,
                                  int32_t* status);
@@ -296,8 +318,9 @@
  * This allows counters to change the direction they are counting in the case of
  * 1X and 2X quadrature encoding only. Any other counter mode isn't supported.
  *
- * @param counterHandle    the counter handle
- * @param reverseDirection true if the value counted should be negated.
+ * @param[in] counterHandle    the counter handle
+ * @param[in] reverseDirection true if the value counted should be negated.
+ * @param[out] status          Error status variable. 0 on success.
  */
 void HAL_SetCounterReverseDirection(HAL_CounterHandle counterHandle,
                                     HAL_Bool reverseDirection, int32_t* status);
diff --git a/hal/src/main/native/include/hal/DIO.h b/hal/src/main/native/include/hal/DIO.h
index 6ffc71f..e094a0d 100644
--- a/hal/src/main/native/include/hal/DIO.h
+++ b/hal/src/main/native/include/hal/DIO.h
@@ -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.
 
 #pragma once
 
@@ -24,21 +21,31 @@
 /**
  * Creates a new instance of a digital port.
  *
- * @param portHandle the port handle to create from
- * @param input      true for input, false for output
- * @return           the created digital handle
+ * @param[in] portHandle         the port handle to create from
+ * @param[in] input              true for input, false for output
+ * @param[in] allocationLocation the location where the allocation is occuring
+ *                               (can be null)
+ * @param[out] status            Error status variable. 0 on success.
+ * @return the created digital handle
  */
 HAL_DigitalHandle HAL_InitializeDIOPort(HAL_PortHandle portHandle,
-                                        HAL_Bool input, int32_t* status);
+                                        HAL_Bool input,
+                                        const char* allocationLocation,
+                                        int32_t* status);
 
 /**
  * Checks if a DIO channel is valid.
  *
  * @param channel the channel number to check
- * @return        true if the channel is correct, otherwise false
+ * @return true if the channel is correct, otherwise false
  */
 HAL_Bool HAL_CheckDIOChannel(int32_t channel);
 
+/**
+ * Frees a DIO port.
+ *
+ * @param dioPortHandle the DIO channel handle
+ */
 void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle);
 
 /**
@@ -52,6 +59,7 @@
 /**
  * Allocates a DO PWM Generator.
  *
+ * @param[out] status Error status variable. 0 on success.
  * @return the allocated digital PWM handle
  */
 HAL_DigitalPWMHandle HAL_AllocateDigitalPWM(int32_t* status);
@@ -59,7 +67,8 @@
 /**
  * Frees the resource associated with a DO PWM generator.
  *
- * @param pwmGenerator the digital PWM handle
+ * @param[in] pwmGenerator the digital PWM handle
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_FreeDigitalPWM(HAL_DigitalPWMHandle pwmGenerator, int32_t* status);
 
@@ -70,15 +79,17 @@
  *
  *  The frequency resolution is logarithmic.
  *
- * @param rate the frequency to output all digital output PWM signals
+ * @param[in] rate the frequency to output all digital output PWM signals
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_SetDigitalPWMRate(double rate, int32_t* status);
 
 /**
  * Configures the duty-cycle of the PWM generator.
  *
- * @param pwmGenerator the digital PWM handle
- * @param dutyCycle    the percent duty cycle to output [0..1]
+ * @param[in] pwmGenerator the digital PWM handle
+ * @param[in] dutyCycle    the percent duty cycle to output [0..1]
+ * @param[out] status      Error status variable. 0 on success.
  */
 void HAL_SetDigitalPWMDutyCycle(HAL_DigitalPWMHandle pwmGenerator,
                                 double dutyCycle, int32_t* status);
@@ -86,8 +97,9 @@
 /**
  * Configures which DO channel the PWM signal is output on.
  *
- * @param pwmGenerator the digital PWM handle
- * @param channel      the channel to output on
+ * @param[in] pwmGenerator the digital PWM handle
+ * @param[in] channel      the channel to output on
+ * @param[out] status      Error status variable. 0 on success.
  */
 void HAL_SetDigitalPWMOutputChannel(HAL_DigitalPWMHandle pwmGenerator,
                                     int32_t channel, int32_t* status);
@@ -95,9 +107,10 @@
 /**
  * Writes a digital value to a DIO channel.
  *
- * @param dioPortHandle the digital port handle
- * @param value         the state to set the digital channel (if it is
- * configured as an output)
+ * @param[in] dioPortHandle the digital port handle
+ * @param[in] value         the state to set the digital channel (if it is
+ *                          configured as an output)
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetDIO(HAL_DigitalHandle dioPortHandle, HAL_Bool value,
                 int32_t* status);
@@ -105,8 +118,9 @@
 /**
  * Sets the direction of a DIO channel.
  *
- * @param dioPortHandle the digital port handle
- * @param input         true to set input, false for output
+ * @param[in] dioPortHandle the digital port handle
+ * @param[in] input         true to set input, false for output
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetDIODirection(HAL_DigitalHandle dioPortHandle, HAL_Bool input,
                          int32_t* status);
@@ -114,16 +128,18 @@
 /**
  * Reads a digital value from a DIO channel.
  *
- * @param dioPortHandle the digital port handle
- * @return              the state of the specified channel
+ * @param[in] dioPortHandle the digital port handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the state of the specified channel
  */
 HAL_Bool HAL_GetDIO(HAL_DigitalHandle dioPortHandle, int32_t* status);
 
 /**
  * Reads the direction of a DIO channel.
  *
- * @param dioPortHandle the digital port handle
- * @return              true for input, false for output
+ * @param[in] dioPortHandle the digital port handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return true for input, false for output
  */
 HAL_Bool HAL_GetDIODirection(HAL_DigitalHandle dioPortHandle, int32_t* status);
 
@@ -133,8 +149,9 @@
  * Write a pulse to the specified digital output channel. There can only be a
  * single pulse going at any time.
  *
- * @param dioPortHandle the digital port handle
- * @param pulseLength   the active length of the pulse (in seconds)
+ * @param[in] dioPortHandle the digital port handle
+ * @param[in] pulseLength   the active length of the pulse (in seconds)
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_Pulse(HAL_DigitalHandle dioPortHandle, double pulseLength,
                int32_t* status);
@@ -142,6 +159,8 @@
 /**
  * Checks a DIO line to see if it is currently generating a pulse.
  *
+ * @param[in] dioPortHandle the digital port handle
+ * @param[out] status Error status variable. 0 on success.
  * @return true if a pulse is in progress, otherwise false
  */
 HAL_Bool HAL_IsPulsing(HAL_DigitalHandle dioPortHandle, int32_t* status);
@@ -149,6 +168,7 @@
 /**
  * Checks if any DIO line is currently generating a pulse.
  *
+ * @param[out] status Error status variable. 0 on success.
  * @return true if a pulse on some line is in progress
  */
 HAL_Bool HAL_IsAnyPulsing(int32_t* status);
@@ -158,9 +178,11 @@
  *
  * Set the filter index used to filter out short pulses.
  *
- * @param dioPortHandle the digital port handle
- * @param filterIndex   the filter index (Must be in the range 0 - 3, where 0
- * means "none" and 1 - 3 means filter # filterIndex - 1)
+ * @param[in] dioPortHandle the digital port handle
+ * @param[in] filterIndex   the filter index (Must be in the range 0 - 3, where
+ *                          0 means "none" and 1 - 3 means filter # filterIndex
+ *                          - 1)
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t filterIndex,
                          int32_t* status);
@@ -170,9 +192,10 @@
  *
  * Gets the filter index used to filter out short pulses.
  *
- * @param dioPortHandle the digital port handle
- * @return filterIndex  the filter index (Must be in the range 0 - 3,
- * where 0 means "none" and 1 - 3 means filter # filterIndex - 1)
+ * @param[in] dioPortHandle the digital port handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return filterIndex  the filter index (Must be in the range 0 - 3, where 0
+ *                      means "none" and 1 - 3 means filter # filterIndex - 1)
  */
 int32_t HAL_GetFilterSelect(HAL_DigitalHandle dioPortHandle, int32_t* status);
 
@@ -183,9 +206,10 @@
  * filter index domains (MXP vs HDR), ignore that distinction for now since it
  * compilicates the interface.  That can be changed later.
  *
- * @param filterIndex the filter index, 0 - 2
- * @param value       the number of cycles that the signal must not transition
- * to be counted as a transition.
+ * @param[in] filterIndex the filter index, 0 - 2
+ * @param[in] value       the number of cycles that the signal must not
+ *                        transition to be counted as a transition.
+ * @param[out] status     Error status variable. 0 on success.
  */
 void HAL_SetFilterPeriod(int32_t filterIndex, int64_t value, int32_t* status);
 
@@ -197,9 +221,8 @@
  * compilicates the interface.  Set status to NiFpga_Status_SoftwareFault if the
  * filter values miss-match.
  *
- * @param filterIndex the filter index, 0 - 2
- * @param value       the number of cycles that the signal must not transition
- * to be counted as a transition.
+ * @param[in] filterIndex the filter index, 0 - 2
+ * @param[out] status     Error status variable. 0 on success.
  */
 int64_t HAL_GetFilterPeriod(int32_t filterIndex, int32_t* status);
 #ifdef __cplusplus
diff --git a/hal/src/main/native/include/hal/DMA.h b/hal/src/main/native/include/hal/DMA.h
index 38aaca2..7610d9b 100644
--- a/hal/src/main/native/include/hal/DMA.h
+++ b/hal/src/main/native/include/hal/DMA.h
@@ -1,28 +1,32 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
-#include <stdint.h>
-
 #include "hal/AnalogTrigger.h"
 #include "hal/Types.h"
 
+/**
+ * @defgroup hal_dma DMA Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
 // clang-format off
 /**
  * The DMA Read Status.
  */
-HAL_ENUM(HAL_DMAReadStatus ) {
+HAL_ENUM(HAL_DMAReadStatus) {
   HAL_DMA_OK = 1,
   HAL_DMA_TIMEOUT = 2,
   HAL_DMA_ERROR = 3,
 };
 // clang-format on
 
+/**
+ * Buffer for containing all DMA data for a specific sample.
+ */
 struct HAL_DMASample {
   uint32_t readBuffer[74];
   int32_t channelOffsets[22];
@@ -35,91 +39,415 @@
 extern "C" {
 #endif
 
+/**
+ * Initializes an object for peforming DMA transfers.
+ *
+ * @param[out] status Error status variable. 0 on success.
+ * @return the created dma handle
+ */
 HAL_DMAHandle HAL_InitializeDMA(int32_t* status);
+
+/**
+ * Frees a DMA object.
+ *
+ * @param handle the dma handle
+ */
 void HAL_FreeDMA(HAL_DMAHandle handle);
 
+/**
+ * Pauses or unpauses a DMA transfer.
+ *
+ * This can only be called while DMA is running.
+ *
+ * @param[in] handle  the dma handle
+ * @param[in] pause   true to pause transfers, false to resume.
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_SetDMAPause(HAL_DMAHandle handle, HAL_Bool pause, int32_t* status);
-void HAL_SetDMARate(HAL_DMAHandle handle, int32_t cycles, int32_t* status);
 
+/**
+ * Sets DMA transfers to occur at a specific timed interval.
+ *
+ * This will remove any external triggers. Only timed or external is supported.
+ *
+ * Only 1 timed period is supported.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle        the dma handle
+ * @param[in] periodSeconds the period to trigger in seconds
+ * @param[out] status       Error status variable. 0 on success.
+ */
+void HAL_SetDMATimedTrigger(HAL_DMAHandle handle, double periodSeconds,
+                            int32_t* status);
+
+/**
+ * Sets DMA transfers to occur at a specific timed interval in FPGA cycles.
+ *
+ * This will remove any external triggers. Only timed or external is supported.
+ *
+ * Only 1 timed period is supported
+ *
+ * The FPGA currently runs at 40 MHz, but this can change.
+ * HAL_GetSystemClockTicksPerMicrosecond can be used to get a computable value
+ * for this.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] cycles the period to trigger in FPGA cycles
+ * @param[out] status Error status variable. 0 on success.
+ */
+void HAL_SetDMATimedTriggerCycles(HAL_DMAHandle handle, uint32_t cycles,
+                                  int32_t* status);
+
+/**
+ * Adds position data for an encoder to be collected by DMA.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] encoderHandle the encoder to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMAEncoder(HAL_DMAHandle handle, HAL_EncoderHandle encoderHandle,
                        int32_t* status);
+
+/**
+ * Adds timer data for an encoder to be collected by DMA.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] encoderHandle the encoder to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMAEncoderPeriod(HAL_DMAHandle handle,
                              HAL_EncoderHandle encoderHandle, int32_t* status);
+
+/**
+ * Adds position data for an counter to be collected by DMA.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] counterHandle the counter to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMACounter(HAL_DMAHandle handle, HAL_CounterHandle counterHandle,
                        int32_t* status);
+
+/**
+ * Adds timer data for an counter to be collected by DMA.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] counterHandle the counter to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMACounterPeriod(HAL_DMAHandle handle,
                              HAL_CounterHandle counterHandle, int32_t* status);
+
+/**
+ * Adds a digital source to be collected by DMA.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] digitalSourceHandle the digital source to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMADigitalSource(HAL_DMAHandle handle,
                              HAL_Handle digitalSourceHandle, int32_t* status);
+
+/**
+ * Adds an analog input to be collected by DMA.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] aInHandle the analog input to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMAAnalogInput(HAL_DMAHandle handle,
                            HAL_AnalogInputHandle aInHandle, int32_t* status);
 
+/**
+ * Adds averaged data of an analog input to be collected by DMA.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] aInHandle the analog input to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMAAveragedAnalogInput(HAL_DMAHandle handle,
                                    HAL_AnalogInputHandle aInHandle,
                                    int32_t* status);
 
+/**
+ * Adds acuumulator data of an analog input to be collected by DMA.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] aInHandle the analog input to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMAAnalogAccumulator(HAL_DMAHandle handle,
                                  HAL_AnalogInputHandle aInHandle,
                                  int32_t* status);
 
+/**
+ * Adds a duty cycle input to be collected by DMA.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] dutyCycleHandle the duty cycle input to add
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_AddDMADutyCycle(HAL_DMAHandle handle,
                          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);
+/**
+ * Sets DMA transfers to occur on an external trigger.
+ *
+ * This will remove any timed trigger set. Only timed or external is supported.
+ *
+ * Up to 8 external triggers are currently supported.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle              the dma handle
+ * @param[in] digitalSourceHandle the digital source handle (either a
+ *                                HAL_AnalogTriggerHandle or a
+ *                                HAL_DigitalHandle)
+ * @param[in] analogTriggerType   the analog trigger type if the source is an
+ *                                analog trigger
+ * @param[in] rising              true to trigger on rising edge
+ * @param[in] falling             true to trigger on falling edge
+ * @param[out] status             Error status variable. 0 on success.
+ * @return the index of the trigger
+ */
+int32_t HAL_SetDMAExternalTrigger(HAL_DMAHandle handle,
+                                  HAL_Handle digitalSourceHandle,
+                                  HAL_AnalogTriggerType analogTriggerType,
+                                  HAL_Bool rising, HAL_Bool falling,
+                                  int32_t* status);
 
+/**
+ * Clear all sensors from the DMA collection list.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[out] status Error status variable. 0 on success.
+ */
+void HAL_ClearDMASensors(HAL_DMAHandle handle, int32_t* status);
+
+/**
+ * Clear all external triggers from the DMA trigger list.
+ *
+ * This can only be called if DMA is not started.
+ *
+ * @param[in] handle the dma handle
+ * @param[out] status Error status variable. 0 on success.
+ */
+void HAL_ClearDMAExternalTriggers(HAL_DMAHandle handle, int32_t* status);
+
+/**
+ * Starts DMA Collection.
+ *
+ * @param[in] handle the dma handle
+ * @param[in] queueDepth the number of objects to be able to queue
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_StartDMA(HAL_DMAHandle handle, int32_t queueDepth, int32_t* status);
+
+/**
+ * Stops DMA Collection.
+ *
+ * @param[in] handle the dma handle
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_StopDMA(HAL_DMAHandle handle, int32_t* status);
 
+/**
+ * Gets the direct pointer to the DMA object.
+ *
+ * This is only to be used if absolute maximum performance is required. This
+ * will only be valid until the handle is freed.
+ *
+ * @param handle the dma handle
+ */
 void* HAL_GetDMADirectPointer(HAL_DMAHandle handle);
 
+/**
+ * Reads a DMA sample using a direct DMA pointer.
+ *
+ * See HAL_ReadDMA for full documentation.
+ *
+ * @param[in] dmaPointer     direct DMA pointer
+ * @param[in] dmaSample      the sample object to place data into
+ * @param[in] timeoutSeconds the time to wait for data to be queued before
+ *                           timing out
+ * @param[in] remainingOut   the number of samples remaining in the queue
+ * @param[out] status        Error status variable. 0 on success.
+ */
 enum HAL_DMAReadStatus HAL_ReadDMADirect(void* dmaPointer,
                                          HAL_DMASample* dmaSample,
-                                         int32_t timeoutMs,
+                                         double timeoutSeconds,
                                          int32_t* remainingOut,
                                          int32_t* status);
 
+/**
+ * Reads a DMA sample from the queue.
+ *
+ *
+ * @param[in] handle         the dma handle
+ * @param[in] dmaSample      the sample object to place data into
+ * @param[in] timeoutSeconds the time to wait for data to be queued before
+ *                           timing out
+ * @param[in] remainingOut   the number of samples remaining in the queue
+ * @param[out] status        Error status variable. 0 on success.
+ * @return the succes result of the sample read
+ */
 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);
 
-// Sampling Code
+// The following are helper functions for reading data from samples
+
+/**
+ * Returns the timestamp of the sample.
+ * This is in the same time domain as HAL_GetFPGATime().
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[out] status Error status variable. 0 on success.
+ * @return timestamp in microseconds since FPGA Initialization
+ */
 uint64_t HAL_GetDMASampleTime(const HAL_DMASample* dmaSample, int32_t* status);
 
+/**
+ * Returns the raw distance data for an encoder from the sample.
+ *
+ * This can be scaled with DistancePerPulse and DecodingScaleFactor to match the
+ * result of GetDistance()
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return raw encoder ticks
+ */
 int32_t HAL_GetDMASampleEncoderRaw(const HAL_DMASample* dmaSample,
                                    HAL_EncoderHandle encoderHandle,
                                    int32_t* status);
 
+/**
+ * Returns the distance data for an counter from the sample.
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] counterHandle the counter handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return counter ticks
+ */
 int32_t HAL_GetDMASampleCounter(const HAL_DMASample* dmaSample,
                                 HAL_CounterHandle counterHandle,
                                 int32_t* status);
 
+/**
+ * Returns the raw period data for an encoder from the sample.
+ *
+ * This can be scaled with DistancePerPulse and DecodingScaleFactor to match the
+ * result of GetRate()
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return raw encoder period
+ */
 int32_t HAL_GetDMASampleEncoderPeriodRaw(const HAL_DMASample* dmaSample,
                                          HAL_EncoderHandle encoderHandle,
                                          int32_t* status);
 
+/**
+ * Returns the period data for an counter from the sample.
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] counterHandle the counter handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return counter period
+ */
 int32_t HAL_GetDMASampleCounterPeriod(const HAL_DMASample* dmaSample,
                                       HAL_CounterHandle counterHandle,
                                       int32_t* status);
+
+/**
+ * Returns the state of a digital source from the sample.
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] dSourceHandle the digital source handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return digital source state
+ */
 HAL_Bool HAL_GetDMASampleDigitalSource(const HAL_DMASample* dmaSample,
                                        HAL_Handle dSourceHandle,
                                        int32_t* status);
+
+/**
+ * Returns the raw analog data for an analog input from the sample.
+ *
+ * This can be scaled with HAL_GetAnalogValueToVolts to match GetVoltage().
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] aInHandle the analog input handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return raw analog data
+ */
 int32_t HAL_GetDMASampleAnalogInputRaw(const HAL_DMASample* dmaSample,
                                        HAL_AnalogInputHandle aInHandle,
                                        int32_t* status);
 
+/**
+ * Returns the raw averaged analog data for an analog input from the sample.
+ *
+ * This can be scaled with HAL_GetAnalogValueToVolts to match
+ * GetAveragedVoltage().
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] aInHandle the analog input handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return raw averaged analog data
+ */
 int32_t HAL_GetDMASampleAveragedAnalogInputRaw(const HAL_DMASample* dmaSample,
                                                HAL_AnalogInputHandle aInHandle,
                                                int32_t* status);
 
+/**
+ * Returns the analog accumulator data for an analog input from the sample.
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] aInHandle the analog input handle
+ * @param[in] count the accumulator count
+ * @param[in] value the accumulator value
+ * @param[out] status Error status variable. 0 on success.
+ */
 void HAL_GetDMASampleAnalogAccumulator(const HAL_DMASample* dmaSample,
                                        HAL_AnalogInputHandle aInHandle,
                                        int64_t* count, int64_t* value,
                                        int32_t* status);
 
+/**
+ * Returns the raw duty cycle input ratio data from the sample.
+ *
+ * Use HAL_GetDutyCycleOutputScaleFactor to scale this to a percentage.
+ *
+ * @param[in] dmaSample the sample to read from
+ * @param[in] dutyCycleHandle the duty cycle handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return raw duty cycle input data
+ */
 int32_t HAL_GetDMASampleDutyCycleOutputRaw(const HAL_DMASample* dmaSample,
                                            HAL_DutyCycleHandle dutyCycleHandle,
                                            int32_t* status);
@@ -127,3 +455,4 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/DriverStation.h b/hal/src/main/native/include/hal/DriverStation.h
index 23595db..1839cfc 100644
--- a/hal/src/main/native/include/hal/DriverStation.h
+++ b/hal/src/main/native/include/hal/DriverStation.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2013-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source 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
 
@@ -30,7 +27,7 @@
  * @param isLVCode  true for a LV error code, false for a standard error code
  * @param details   the details of the error
  * @param location  the file location of the errror
- * @param callstack the callstack of the error
+ * @param callStack the callstack of the error
  * @param printMsg  true to print the error message to stdout as well as to the
  * DS
  */
@@ -50,15 +47,15 @@
  * The control work contains the robot state.
  *
  * @param controlWord the control word (out)
- * @return            the error code, or 0 for success
+ * @return the error code, or 0 for success
  */
 int32_t HAL_GetControlWord(HAL_ControlWord* controlWord);
 
 /**
  * Gets the current alliance station ID.
  *
- * @param status the error code, or 0 for success
- * @return       the alliance station ID
+ * @param[out] status the error code, or 0 for success
+ * @return the alliance station ID
  */
 HAL_AllianceStationID HAL_GetAllianceStation(int32_t* status);
 
@@ -67,7 +64,7 @@
  *
  * @param joystickNum the joystick number
  * @param axes        the axes values (output)
- * @return            the error code, or 0 for success
+ * @return the error code, or 0 for success
  */
 int32_t HAL_GetJoystickAxes(int32_t joystickNum, HAL_JoystickAxes* axes);
 
@@ -76,7 +73,7 @@
  *
  * @param joystickNum the joystick number
  * @param povs        the POV values (output)
- * @return            the error code, or 0 for success
+ * @return the error code, or 0 for success
  */
 int32_t HAL_GetJoystickPOVs(int32_t joystickNum, HAL_JoystickPOVs* povs);
 
@@ -85,7 +82,7 @@
  *
  * @param joystickNum the joystick number
  * @param buttons     the button values (output)
- * @return            the error code, or 0 for success
+ * @return the error code, or 0 for success
  */
 int32_t HAL_GetJoystickButtons(int32_t joystickNum,
                                HAL_JoystickButtons* buttons);
@@ -93,14 +90,15 @@
 /**
  * Retrieves the Joystick Descriptor for particular slot.
  *
- * @param desc [out] descriptor (data transfer object) to fill in.  desc is
- * filled in regardless of success. In other words, if descriptor is not
- * available, desc is filled in with default values matching the init-values in
- * Java and C++ Driverstation for when caller requests a too-large joystick
- * index.
- *
+ * @param joystickNum the joystick number
+ * @param[out] desc   descriptor (data transfer object) to fill in. desc is
+ *                    filled in regardless of success. In other words, if
+ *                    descriptor is not available, desc is filled in with
+ *                    default values matching the init-values in Java and C++
+ *                    Driver Station for when caller requests a too-large
+ *                    joystick index.
  * @return error code reported from Network Comm back-end.  Zero is good,
- * nonzero is bad.
+ *         nonzero is bad.
  */
 int32_t HAL_GetJoystickDescriptor(int32_t joystickNum,
                                   HAL_JoystickDescriptor* desc);
@@ -109,7 +107,7 @@
  * Gets is a specific joystick is considered to be an XBox controller.
  *
  * @param joystickNum the joystick number
- * @return            true if xbox, false otherwise
+ * @return true if xbox, false otherwise
  */
 HAL_Bool HAL_GetJoystickIsXbox(int32_t joystickNum);
 
@@ -120,7 +118,7 @@
  * the joystick uses.
  *
  * @param joystickNum the joystick number
- * @return            the enumerated joystick type
+ * @return the enumerated joystick type
  */
 int32_t HAL_GetJoystickType(int32_t joystickNum);
 
@@ -132,7 +130,7 @@
  * Will be null terminated.
  *
  * @param joystickNum the joystick number
- * @return            the joystick name
+ * @return the joystick name
  */
 char* HAL_GetJoystickName(int32_t joystickNum);
 
@@ -151,18 +149,18 @@
  *
  * @param joystickNum the joystick number
  * @param axis        the axis number
- * @return            the enumerated axis type
+ * @return the enumerated axis type
  */
 int32_t HAL_GetJoystickAxisType(int32_t joystickNum, int32_t axis);
 
 /**
  * Set joystick outputs.
  *
- * @param joystickNum the joystick numer
+ * @param joystickNum the joystick number
  * @param outputs     bitmask of outputs, 1 for on 0 for off
  * @param leftRumble  the left rumble value (0-FFFF)
  * @param rightRumble the right rumble value (0-FFFF)
- * @return            the error code, or 0 for success
+ * @return the error code, or 0 for success
  */
 int32_t HAL_SetJoystickOutputs(int32_t joystickNum, int64_t outputs,
                                int32_t leftRumble, int32_t rightRumble);
@@ -180,7 +178,7 @@
  * The Practice Match function of the DS approximates the behavior seen on
  * the field.
  *
- * @param status the error code, or 0 for success
+ * @param[out] status the error code, or 0 for success
  * @return time remaining in current match period (auto or teleop)
  */
 double HAL_GetMatchTime(int32_t* status);
@@ -188,8 +186,8 @@
 /**
  * Gets info about a specific match.
  *
- * @param info the match info (output)
- * @return     the error code, or 0 for success
+ * @param[in] info the match info (output)
+ * @return the error code, or 0 for success
  */
 int32_t HAL_GetMatchInfo(HAL_MatchInfo* info);
 
@@ -220,8 +218,8 @@
  * forever. Otherwise, it will wait until either a new packet, or the timeout
  * time has passed.
  *
- * @param timeout timeout in seconds
- * @return        true for new data, false for timeout
+ * @param[in] timeout timeout in seconds
+ * @return true for new data, false for timeout
  */
 HAL_Bool HAL_WaitForDSDataTimeout(double timeout);
 
@@ -243,7 +241,7 @@
  * Sets the disabled flag in the DS.
  *
  * This is used for the DS to ensure the robot is properly responding to its
- * state request. Ensure this get called about every 50ms, or the robot will be
+ * state request. Ensure this gets called about every 50ms, or the robot will be
  * disabled by the DS.
  */
 void HAL_ObserveUserProgramDisabled(void);
@@ -252,7 +250,7 @@
  * Sets the autonomous enabled flag in the DS.
  *
  * This is used for the DS to ensure the robot is properly responding to its
- * state request. Ensure this get called about every 50ms, or the robot will be
+ * state request. Ensure this gets called about every 50ms, or the robot will be
  * disabled by the DS.
  */
 void HAL_ObserveUserProgramAutonomous(void);
@@ -261,7 +259,7 @@
  * Sets the teleoperated enabled flag in the DS.
  *
  * This is used for the DS to ensure the robot is properly responding to its
- * state request. Ensure this get called about every 50ms, or the robot will be
+ * state request. Ensure this gets called about every 50ms, or the robot will be
  * disabled by the DS.
  */
 void HAL_ObserveUserProgramTeleop(void);
@@ -270,7 +268,7 @@
  * Sets the test mode flag in the DS.
  *
  * This is used for the DS to ensure the robot is properly responding to its
- * state request. Ensure this get called about every 50ms, or the robot will be
+ * state request. Ensure this gets called about every 50ms, or the robot will be
  * disabled by the DS.
  */
 void HAL_ObserveUserProgramTest(void);
diff --git a/hal/src/main/native/include/hal/DriverStationTypes.h b/hal/src/main/native/include/hal/DriverStationTypes.h
index 7c5d6f6..21f9088 100644
--- a/hal/src/main/native/include/hal/DriverStationTypes.h
+++ b/hal/src/main/native/include/hal/DriverStationTypes.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
diff --git a/hal/src/main/native/include/hal/DutyCycle.h b/hal/src/main/native/include/hal/DutyCycle.h
index 357d8f3..05b654b 100644
--- a/hal/src/main/native/include/hal/DutyCycle.h
+++ b/hal/src/main/native/include/hal/DutyCycle.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -23,10 +20,12 @@
 /**
  * Initialize a DutyCycle input.
  *
- * @param digitalSourceHandle the digital source to use (either a
- * HAL_DigitalHandle or a HAL_AnalogTriggerHandle)
- * @param triggerType the analog trigger type of the source if it is
- * an analog trigger
+ * @param[in] digitalSourceHandle the digital source to use (either a
+ *                                 HAL_DigitalHandle or a
+ *                                 HAL_AnalogTriggerHandle)
+ * @param[in] triggerType the analog trigger type of the source if it is
+ *                         an analog trigger
+ * @param[out] status Error status variable. 0 on success.
  * @return thre created duty cycle handle
  */
 HAL_DutyCycleHandle HAL_InitializeDutyCycle(HAL_Handle digitalSourceHandle,
@@ -52,7 +51,8 @@
 /**
  * Get the frequency of the duty cycle signal.
  *
- * @param dutyCycleHandle the duty cycle handle
+ * @param[in] dutyCycleHandle the duty cycle handle
+ * @param[out] status Error status variable. 0 on success.
  * @return frequency in Hertz
  */
 int32_t HAL_GetDutyCycleFrequency(HAL_DutyCycleHandle dutyCycleHandle,
@@ -63,7 +63,8 @@
  *
  * <p> 0 means always low, 1 means always high.
  *
- * @param dutyCycleHandle the duty cycle handle
+ * @param[in] dutyCycleHandle the duty cycle handle
+ * @param[out] status Error status variable. 0 on success.
  * @return output ratio between 0 and 1
  */
 double HAL_GetDutyCycleOutput(HAL_DutyCycleHandle dutyCycleHandle,
@@ -75,7 +76,8 @@
  * <p> 0 means always low, an output equal to
  * GetOutputScaleFactor() means always high.
  *
- * @param dutyCycleHandle the duty cycle handle
+ * @param[in] dutyCycleHandle the duty cycle handle
+ * @param[out] status Error status variable. 0 on success.
  * @return output ratio in raw units
  */
 int32_t HAL_GetDutyCycleOutputRaw(HAL_DutyCycleHandle dutyCycleHandle,
@@ -88,7 +90,8 @@
  * down to 0. Divide the result of getOutputRaw by this in order to get the
  * percentage between 0 and 1.
  *
- * @param dutyCycleHandle the duty cycle handle
+ * @param[in] dutyCycleHandle the duty cycle handle
+ * @param[out] status Error status variable. 0 on success.
  * @return the output scale factor
  */
 int32_t HAL_GetDutyCycleOutputScaleFactor(HAL_DutyCycleHandle dutyCycleHandle,
@@ -97,7 +100,8 @@
 /**
  * Get the FPGA index for the DutyCycle.
  *
- * @param dutyCycleHandle the duty cycle handle
+ * @param[in] dutyCycleHandle the duty cycle handle
+ * @param[out] status Error status variable. 0 on success.
  * @return the FPGA index
  */
 int32_t HAL_GetDutyCycleFPGAIndex(HAL_DutyCycleHandle dutyCycleHandle,
diff --git a/hal/src/main/native/include/hal/Encoder.h b/hal/src/main/native/include/hal/Encoder.h
index 9d2b5d0..a6bf4af 100644
--- a/hal/src/main/native/include/hal/Encoder.h
+++ b/hal/src/main/native/include/hal/Encoder.h
@@ -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.
 
 #pragma once
 
@@ -46,18 +43,19 @@
 /**
  * Initializes an encoder.
  *
- * @param digitalSourceHandleA the A source (either a HAL_DigitalHandle or a
- * HAL_AnalogTriggerHandle)
- * @param analogTriggerTypeA   the analog trigger type of the A source if it is
- * an analog trigger
- * @param digitalSourceHandleB the B source (either a HAL_DigitalHandle or a
- * HAL_AnalogTriggerHandle)
- * @param analogTriggerTypeB   the analog trigger type of the B source if it is
- * an analog trigger
- * @param reverseDirection     true to reverse the counting direction from
- * standard, otherwise false
- * @param encodingType         the encoding type
-   @return                     the created encoder handle
+ * @param[in] digitalSourceHandleA the A source (either a HAL_DigitalHandle or a
+ *                                 HAL_AnalogTriggerHandle)
+ * @param[in] analogTriggerTypeA   the analog trigger type of the A source if it
+ *                                 is an analog trigger
+ * @param[in] digitalSourceHandleB the B source (either a HAL_DigitalHandle or a
+ *                                 HAL_AnalogTriggerHandle)
+ * @param[in] analogTriggerTypeB   the analog trigger type of the B source if it
+ *                                 is an analog trigger
+ * @param[in] reverseDirection     true to reverse the counting direction from
+ *                                 standard, otherwise false
+ * @param[in] encodingType         the encoding type
+ * @param[out] status              Error status variable. 0 on success.
+ * @return the created encoder handle
  */
 HAL_EncoderHandle HAL_InitializeEncoder(
     HAL_Handle digitalSourceHandleA, HAL_AnalogTriggerType analogTriggerTypeA,
@@ -68,7 +66,8 @@
 /**
  * Frees an encoder.
  *
- * @param encoderHandle the encoder handle
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_FreeEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
 
@@ -86,7 +85,8 @@
  *
  * This is scaled by the value passed duing initialization to encodingType.
  *
- * @param encoderHandle the encoder handle
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status Error status variable. 0 on success.
  * @return the current scaled count
  */
 int32_t HAL_GetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
@@ -96,8 +96,9 @@
  *
  * This is not scaled by any values.
  *
- * @param encoderHandle the encoder handle
- * @return              the raw encoder count
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the raw encoder count
  */
 int32_t HAL_GetEncoderRaw(HAL_EncoderHandle encoderHandle, int32_t* status);
 
@@ -106,8 +107,9 @@
  *
  * This is set by the value passed during initialization to encodingType.
  *
- * @param encoderHandle the encoder handle
- * @return              the encoder scale value
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the encoder scale value
  */
 int32_t HAL_GetEncoderEncodingScale(HAL_EncoderHandle encoderHandle,
                                     int32_t* status);
@@ -118,8 +120,8 @@
  * Read the value at this instant. It may still be running, so it reflects the
  * current value. Next time it is read, it might have a different value.
  *
- * @param encoderHandle the encoder handle
- * @return              the current encoder value
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_ResetEncoder(HAL_EncoderHandle encoderHandle, int32_t* status);
 
@@ -129,8 +131,9 @@
  * Returns the time interval of the most recent count. This can be used for
  * velocity calculations to determine shaft speed.
  *
- * @param encoderHandle the encoder handle
- * @returns             the period of the last two pulses in units of seconds
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @returns the period of the last two pulses in units of seconds
  */
 double HAL_GetEncoderPeriod(HAL_EncoderHandle encoderHandle, int32_t* status);
 
@@ -141,9 +144,10 @@
  * used to determine the "stopped" state of the encoder using the
  * HAL_GetEncoderStopped method.
  *
- * @param encoderHandle the encoder handle
- * @param maxPeriod     the maximum period where the counted device is
- * considered moving in seconds
+ * @param[in] encoderHandle the encoder handle
+ * @param[in] maxPeriod     the maximum period where the counted device is
+ *                          considered moving in seconds
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetEncoderMaxPeriod(HAL_EncoderHandle encoderHandle, double maxPeriod,
                              int32_t* status);
@@ -155,9 +159,10 @@
  * using the SetMaxPeriod method. If the clock exceeds the MaxPeriod, then the
  * device (and encoder) are assumed to be stopped and it returns true.
  *
- * @param encoderHandle the encoder handle
- * @return              true if the most recent encoder period exceeds the
- * MaxPeriod value set by SetMaxPeriod
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return true if the most recent encoder period exceeds the MaxPeriod value
+ *         set by SetMaxPeriod
  */
 HAL_Bool HAL_GetEncoderStopped(HAL_EncoderHandle encoderHandle,
                                int32_t* status);
@@ -165,8 +170,9 @@
 /**
  * Gets the last direction the encoder value changed.
  *
- * @param encoderHandle the encoder handle
- * @return              the last direction the encoder value changed
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the last direction the encoder value changed
  */
 HAL_Bool HAL_GetEncoderDirection(HAL_EncoderHandle encoderHandle,
                                  int32_t* status);
@@ -177,9 +183,10 @@
  * This is the encoder count scaled by the distance per pulse set for the
  * encoder.
  *
- * @param encoderHandle the encoder handle
- * @return              the encoder distance (units are determined by the units
- * passed to HAL_SetEncoderDistancePerPulse)
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the encoder distance (units are determined by the units
+ *                      passed to HAL_SetEncoderDistancePerPulse)
  */
 double HAL_GetEncoderDistance(HAL_EncoderHandle encoderHandle, int32_t* status);
 
@@ -189,9 +196,10 @@
  * This is the encoder period scaled by the distance per pulse set for the
  * encoder.
  *
- * @param encoderHandle the encoder handle
- * @return              the encoder rate (units are determined by the units
- * passed to HAL_SetEncoderDistancePerPulse, time value is seconds)
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the encoder rate (units are determined by the units passed to
+ *         HAL_SetEncoderDistancePerPulse, time value is seconds)
  */
 double HAL_GetEncoderRate(HAL_EncoderHandle encoderHandle, int32_t* status);
 
@@ -201,10 +209,12 @@
  * Units need to match what is set by HAL_SetEncoderDistancePerPulse, with time
  * as seconds.
  *
- * @param encoderHandle the encoder handle
- * @param minRate       the minimum rate to be considered moving (units are
- * determined by the units passed to HAL_SetEncoderDistancePerPulse, time value
- * is seconds)
+ * @param[in] encoderHandle the encoder handle
+ * @param[in] minRate       the minimum rate to be considered moving (units are
+ *                          determined by the units passed to
+ *                          HAL_SetEncoderDistancePerPulse, time value is
+ *                          seconds)
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetEncoderMinRate(HAL_EncoderHandle encoderHandle, double minRate,
                            int32_t* status);
@@ -213,9 +223,10 @@
  * Sets the distance traveled per encoder pulse. This is used as a scaling
  * factor for the rate and distance calls.
  *
- * @param encoderHandle    the encoder handle
- * @param distancePerPulse the distance traveled per encoder pulse (units user
- * defined)
+ * @param[in] encoderHandle    the encoder handle
+ * @param[in] distancePerPulse the distance traveled per encoder pulse (units
+ *                             user defined)
+ * @param[out] status          Error status variable. 0 on success.
  */
 void HAL_SetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
                                     double distancePerPulse, int32_t* status);
@@ -225,8 +236,9 @@
  *
  * Note that this is not a toggle. It is an absolute set.
  *
- * @param encoderHandle    the encoder handle
- * @param reverseDirection true to reverse the direction, false to not.
+ * @param[in] encoderHandle    the encoder handle
+ * @param[in] reverseDirection true to reverse the direction, false to not.
+ * @param[out] status          Error status variable. 0 on success.
  */
 void HAL_SetEncoderReverseDirection(HAL_EncoderHandle encoderHandle,
                                     HAL_Bool reverseDirection, int32_t* status);
@@ -234,8 +246,9 @@
 /**
  * Sets the number of encoder samples to average when calculating encoder rate.
  *
- * @param encoderHandle    the encoder handle
- * @param samplesToAverage the number of samples to average
+ * @param[in] encoderHandle    the encoder handle
+ * @param[in] samplesToAverage the number of samples to average
+ * @param[out] status          Error status variable. 0 on success.
  */
 void HAL_SetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
                                     int32_t samplesToAverage, int32_t* status);
@@ -243,8 +256,9 @@
 /**
  * Gets the current samples to average value.
  *
- * @param encoderHandle the encoder handle
- * @return              the current samples to average value
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the current samples to average value
  */
 int32_t HAL_GetEncoderSamplesToAverage(HAL_EncoderHandle encoderHandle,
                                        int32_t* status);
@@ -255,12 +269,14 @@
  * The index pulse can be used to cause an encoder to reset based on an external
  * input.
  *
- * @param encoderHandle       the encoder handle
- * @param digitalSourceHandle the index source handle (either a
- * HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
- * @param analogTriggerType   the analog trigger type if the source is an analog
- * trigger
- * @param type                the index triggering type
+ * @param[in] encoderHandle       the encoder handle
+ * @param[in] digitalSourceHandle the index source handle (either a
+ *                                HAL_AnalogTriggerHandle or a
+ *                                HAL_DigitalHandle)
+ * @param[in] analogTriggerType   the analog trigger type if the source is an
+ *                                analog trigger
+ * @param[in] type                the index triggering type
+ * @param[out] status             Error status variable. 0 on success.
  */
 void HAL_SetEncoderIndexSource(HAL_EncoderHandle encoderHandle,
                                HAL_Handle digitalSourceHandle,
@@ -270,8 +286,9 @@
 /**
  * Gets the FPGA index of the encoder.
  *
- * @param encoderHandle the encoder handle
- * @return              the FPGA index of the encoder
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the FPGA index of the encoder
  */
 int32_t HAL_GetEncoderFPGAIndex(HAL_EncoderHandle encoderHandle,
                                 int32_t* status);
@@ -281,8 +298,9 @@
  *
  * This is used to perform the scaling from raw to type scaled values.
  *
- * @param encoderHandle the encoder handle
- * @return              the scale value for the encoder
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the scale value for the encoder
  */
 double HAL_GetEncoderDecodingScaleFactor(HAL_EncoderHandle encoderHandle,
                                          int32_t* status);
@@ -290,8 +308,9 @@
 /**
  * Gets the user set distance per pulse of the encoder.
  *
- * @param encoderHandle the encoder handle
- * @return              the set distance per pulse
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the set distance per pulse
  */
 double HAL_GetEncoderDistancePerPulse(HAL_EncoderHandle encoderHandle,
                                       int32_t* status);
@@ -299,8 +318,9 @@
 /**
  * Gets the encoding type of the encoder.
  *
- * @param encoderHandle the encoder handle
- * @return              the encoding type
+ * @param[in] encoderHandle the encoder handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the encoding type
  */
 HAL_EncoderEncodingType HAL_GetEncoderEncodingType(
     HAL_EncoderHandle encoderHandle, int32_t* status);
diff --git a/hal/src/main/native/include/hal/Errors.h b/hal/src/main/native/include/hal/Errors.h
index 9f74f8c..b24bfb7 100644
--- a/hal/src/main/native/include/hal/Errors.h
+++ b/hal/src/main/native/include/hal/Errors.h
@@ -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.
 
 #pragma once
 
@@ -44,6 +41,8 @@
 #define ERR_FRCSystem_NoDSConnection_MESSAGE \
   "FRCSystem: No driver station connected"
 
+#define HAL_SUCCESS 0
+
 #define SAMPLE_RATE_TOO_HIGH 1001
 #define SAMPLE_RATE_TOO_HIGH_MESSAGE \
   "HAL: Analog module sample rate is too high"
@@ -102,6 +101,10 @@
 #define HAL_INVALID_DMA_ADDITION_MESSAGE \
   "HAL_AddDMA() only works before HAL_StartDMA()"
 
+#define HAL_INVALID_DMA_STATE -1103
+#define HAL_INVALID_DMA_STATE_MESSAGE \
+  "HAL_SetPause() only works before HAL_StartDMA()"
+
 #define HAL_SERIAL_PORT_NOT_FOUND -1123
 #define HAL_SERIAL_PORT_NOT_FOUND_MESSAGE \
   "HAL: The specified serial port device was not found"
@@ -116,7 +119,7 @@
 
 #define HAL_THREAD_PRIORITY_ERROR -1152
 #define HAL_THREAD_PRIORITY_ERROR_MESSAGE \
-  "HAL: Getting or setting the priority of a thread has failed";
+  "HAL: Getting or setting the priority of a thread has failed"
 
 #define HAL_THREAD_PRIORITY_RANGE_ERROR -1153
 #define HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE \
@@ -128,11 +131,20 @@
 #define HAL_SIM_NOT_SUPPORTED -1155
 #define HAL_SIM_NOT_SUPPORTED_MESSAGE "HAL: Method not supported in sim"
 
+#define HAL_USE_LAST_ERROR -1156
+#define HAL_USE_LAST_ERROR_MESSAGE \
+  "HAL: Use HAL_GetLastError(status) to get last error"
+
+#define HAL_CONSOLE_OUT_ENABLED_ERROR -1157
+#define HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE                           \
+  "HAL: Onboard serial port is requested, but Console Out is enabled. " \
+  "Disable Console Out using imaging tool"
+
 #define HAL_CAN_BUFFER_OVERRUN -35007
 #define HAL_CAN_BUFFER_OVERRUN_MESSAGE \
   "HAL: CAN Output Buffer Full. Ensure a device is attached"
 
-#define VI_ERROR_SYSTEM_ERROR_MESSAGE "HAL - VISA: System Error";
+#define VI_ERROR_SYSTEM_ERROR_MESSAGE "HAL - VISA: System Error"
 #define VI_ERROR_INV_OBJECT_MESSAGE "HAL - VISA: Invalid Object"
 #define VI_ERROR_RSRC_LOCKED_MESSAGE "HAL - VISA: Resource Locked"
 #define VI_ERROR_RSRC_NFOUND_MESSAGE "HAL - VISA: Resource Not Found"
diff --git a/hal/src/main/native/include/hal/Extensions.h b/hal/src/main/native/include/hal/Extensions.h
index 13de7f8..ad3f733 100644
--- a/hal/src/main/native/include/hal/Extensions.h
+++ b/hal/src/main/native/include/hal/Extensions.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
 
@@ -35,7 +32,7 @@
  * Expected to be called internally, not by users.
  *
  * @param library the library path
- * @return        the succes state of the initialization
+ * @return the succes state of the initialization
  */
 int HAL_LoadOneExtension(const char* library);
 
@@ -43,7 +40,7 @@
  * Loads any extra halsim libraries provided in the HALSIM_EXTENSIONS
  * environment variable.
  *
- * @return        the succes state of the initialization
+ * @return the succes state of the initialization
  */
 int HAL_LoadExtensions(void);
 
diff --git a/hal/src/main/native/include/hal/HAL.h b/hal/src/main/native/include/hal/HAL.h
index 4412886..0d60237 100644
--- a/hal/src/main/native/include/hal/HAL.h
+++ b/hal/src/main/native/include/hal/HAL.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2013-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -17,7 +14,7 @@
 #include "hal/AnalogTrigger.h"
 #include "hal/CAN.h"
 #include "hal/CANAPI.h"
-#include "hal/Compressor.h"
+#include "hal/CTREPCM.h"
 #include "hal/Constants.h"
 #include "hal/Counter.h"
 #include "hal/DIO.h"
@@ -30,7 +27,6 @@
 #include "hal/Interrupts.h"
 #include "hal/Main.h"
 #include "hal/Notifier.h"
-#include "hal/PDP.h"
 #include "hal/PWM.h"
 #include "hal/Ports.h"
 #include "hal/Power.h"
@@ -38,7 +34,6 @@
 #include "hal/SPI.h"
 #include "hal/SerialPort.h"
 #include "hal/SimDevice.h"
-#include "hal/Solenoid.h"
 #include "hal/Threads.h"
 #include "hal/Types.h"
 #include "hal/Value.h"
diff --git a/hal/src/main/native/include/hal/HALBase.h b/hal/src/main/native/include/hal/HALBase.h
index ee5b054..b31ec75 100644
--- a/hal/src/main/native/include/hal/HALBase.h
+++ b/hal/src/main/native/include/hal/HALBase.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -18,7 +15,7 @@
  */
 
 // clang-format off
-HAL_ENUM(HAL_RuntimeType) { HAL_Athena, HAL_Mock };
+HAL_ENUM(HAL_RuntimeType) { HAL_Runtime_RoboRIO, HAL_Runtime_RoboRIO2, HAL_Runtime_Simulation };
 // clang-format on
 
 #ifdef __cplusplus
@@ -26,10 +23,23 @@
 #endif
 
 /**
+ * Gets the last error set on this thread, or the message for the status code.
+ *
+ * If passed HAL_USE_LAST_ERROR, the last error set on the thread will be
+ * returned.
+ *
+ * @param[out] status the status code, set to the error status code if input is
+ *               HAL_USE_LAST_ERROR
+ * @return the error message for the code. This does not need to be freed,
+ *               but can be overwritten by another hal call on the same thread.
+ */
+const char* HAL_GetLastError(int32_t* status);
+
+/**
  * Gets the error message for a specific status code.
  *
  * @param code the status code
- * @return     the error message for the code. This does not need to be freed.
+ * @return the error message for the code. This does not need to be freed.
  */
 const char* HAL_GetErrorMessage(int32_t code);
 
@@ -38,6 +48,7 @@
  *
  * For now, expect this to be competition year.
  *
+ * @param[out] status the error code, or 0 for success
  * @return FPGA Version number.
  */
 int32_t HAL_GetFPGAVersion(int32_t* status);
@@ -50,15 +61,22 @@
  * the next 8 bits are the Minor Revision.
  * The 12 least significant bits are the Build Number.
  *
+ * @param[out] status the error code, or 0 for success
  * @return FPGA Revision number.
  */
 int64_t HAL_GetFPGARevision(int32_t* status);
 
+/**
+ * Returns the runtime type of the HAL.
+ *
+ * @return HAL Runtime Type
+ */
 HAL_RuntimeType HAL_GetRuntimeType(void);
 
 /**
  * Gets the state of the "USER" button on the roboRIO.
  *
+ * @param[out] status the error code, or 0 for success
  * @return true if the button is currently pressed down
  */
 HAL_Bool HAL_GetFPGAButton(int32_t* status);
@@ -66,6 +84,7 @@
 /**
  * Gets if the system outputs are currently active
  *
+ * @param[out] status the error code, or 0 for success
  * @return true if the system outputs are active, false if disabled
  */
 HAL_Bool HAL_GetSystemActive(int32_t* status);
@@ -73,6 +92,7 @@
 /**
  * Gets if the system is in a browned out state.
  *
+ * @param[out] status the error code, or 0 for success
  * @return true if the system is in a low voltage brown out, false otherwise
  */
 HAL_Bool HAL_GetBrownedOut(int32_t* status);
@@ -83,7 +103,7 @@
  * The created handle does not need to be freed.
  *
  * @param channel the channel number
- * @return        the created port
+ * @return the created port
  */
 HAL_PortHandle HAL_GetPort(int32_t channel);
 
@@ -97,13 +117,14 @@
  *
  * @param module  the module number
  * @param channel the channel number
- * @return        the created port
+ * @return the created port
  */
 HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel);
 
 /**
  * Reads the microsecond-resolution timer on the FPGA.
  *
+ * @param[out] status the error code, or 0 for success
  * @return The current time in microseconds according to the FPGA (since FPGA
  * reset).
  */
@@ -118,10 +139,12 @@
  * bottom 32 bits of the timestamp and expanding it, you will be off by
  * multiples of 1<<32 microseconds.
  *
+ * @param[in] unexpandedLower 32 bit FPGA time
+ * @param[out] status the error code, or 0 for success
  * @return The current time in microseconds according to the FPGA (since FPGA
- * reset) as a 64 bit number.
+ *         reset) as a 64 bit number.
  */
-uint64_t HAL_ExpandFPGATime(uint32_t unexpanded_lower, int32_t* status);
+uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status);
 
 /**
  * Call this to start up HAL. This is required for robot programs.
@@ -145,7 +168,7 @@
  *
  * @param timeout the initialization timeout (ms)
  * @param mode    the initialization mode (see remarks)
- * @return        true if initialization was successful, otherwise false.
+ * @return true if initialization was successful, otherwise false.
  */
 HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode);
 
@@ -157,6 +180,18 @@
  */
 void HAL_Shutdown(void);
 
+/**
+ * Calls registered SimPeriodic "before" callbacks (only in simulation mode).
+ * This should be called prior to user code periodic simulation functions.
+ */
+void HAL_SimPeriodicBefore(void);
+
+/**
+ * Calls registered SimPeriodic "after" callbacks (only in simulation mode).
+ * This should be called after user code periodic simulation functions.
+ */
+void HAL_SimPeriodicAfter(void);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/hal/src/main/native/include/hal/I2C.h b/hal/src/main/native/include/hal/I2C.h
index 4147cbb..4e5c007 100644
--- a/hal/src/main/native/include/hal/I2C.h
+++ b/hal/src/main/native/include/hal/I2C.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
 
@@ -27,7 +24,8 @@
  * Opens the port if necessary and saves the handle.
  * If opening the MXP port, also sets up the channel functions appropriately.
  *
- * @param port The port to open, 0 for the on-board, 1 for the MXP.
+ * @param[in] port    The port to open, 0 for the on-board, 1 for the MXP.
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status);
 
@@ -38,6 +36,8 @@
  * over each transaction.
  *
  * @param port The I2C port, 0 for the on-board, 1 for the MXP.
+ * @param deviceAddress The address of the register on the device to be
+ *                      read/written.
  * @param dataToSend Buffer of data to send as part of the transaction.
  * @param sendSize Number of bytes to send as part of the transaction.
  * @param dataReceived Buffer to read data into.
@@ -55,9 +55,10 @@
  *   transaction is complete.
  *
  * @param port The I2C port, 0 for the on-board, 1 for the MXP.
- * @param registerAddress The address of the register on the device to be
- * written.
- * @param data The byte to write to the register on the device.
+ * @param deviceAddress The address of the register on the device to be
+ *                      written.
+ * @param dataToSend The byte to write to the register on the device.
+ * @param sendSize Number of bytes to send.
  * @return >= 0 on success or -1 on transfer abort.
  */
 int32_t HAL_WriteI2C(HAL_I2CPort port, int32_t deviceAddress,
@@ -71,7 +72,7 @@
  *   you to read consecutive registers on a device in a single transaction.
  *
  * @param port The I2C port, 0 for the on-board, 1 for the MXP.
- * @param registerAddress The register to read first in the transaction.
+ * @param deviceAddress The register to read first in the transaction.
  * @param count The number of bytes to read in the transaction.
  * @param buffer A pointer to the array of bytes to store the data read from the
  * device.
diff --git a/hal/src/main/native/include/hal/I2CTypes.h b/hal/src/main/native/include/hal/I2CTypes.h
index b5e8235..6aac0fb 100644
--- a/hal/src/main/native/include/hal/I2CTypes.h
+++ b/hal/src/main/native/include/hal/I2CTypes.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
diff --git a/hal/src/main/native/include/hal/Interrupts.h b/hal/src/main/native/include/hal/Interrupts.h
index ff68d48..def800c 100644
--- a/hal/src/main/native/include/hal/Interrupts.h
+++ b/hal/src/main/native/include/hal/Interrupts.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
 
@@ -22,67 +19,45 @@
 extern "C" {
 #endif
 
-typedef void (*HAL_InterruptHandlerFunction)(uint32_t interruptAssertedMask,
-                                             void* param);
-
 /**
  * Initializes an interrupt.
  *
- * @param watcher true for synchronous interrupts, false for asynchronous
- * @return        the created interrupt handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the created interrupt handle
  */
-HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher, int32_t* status);
+HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status);
 
 /**
  * Frees an interrupt.
  *
  * @param interruptHandle the interrupt handle
- * @return                the param passed to the interrupt, or nullptr if one
- * wasn't passed.
  */
-void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
+void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle);
 
 /**
  * In synchronous mode, waits for the defined interrupt to occur.
  *
- * @param interruptHandle the interrupt handle
- * @param timeout        timeout in seconds
- * @param ignorePrevious if true, ignore interrupts that happened before
- * waitForInterrupt was called
- * @return               the mask of interrupts that fired
+ * @param[in] interruptHandle the interrupt handle
+ * @param[in] timeout         timeout in seconds
+ * @param[in] ignorePrevious  if true, ignore interrupts that happened before
+ *                            waitForInterrupt was called
+ * @param[out] status         Error status variable. 0 on success.
+ * @return the mask of interrupts that fired
  */
 int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
                              double timeout, HAL_Bool ignorePrevious,
                              int32_t* status);
 
 /**
- * Enables interrupts to occur on this input.
- *
- * Interrupts are disabled when the RequestInterrupt call is made. This gives
- * time to do the setup of the other options before starting to field
- * interrupts.
- *
- * @param interruptHandle the interrupt handle
- */
-void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
-
-/**
- * Disables interrupts without without deallocating structures.
- *
- * @param interruptHandle the interrupt handle
- */
-void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
-                           int32_t* status);
-
-/**
  * Returns the timestamp for the rising interrupt that occurred most recently.
  *
  * This is in the same time domain as HAL_GetFPGATime().  It only contains the
  * bottom 32 bits of the timestamp.  If your robot has been running for over 1
  * hour, you will need to fill in the upper 32 bits yourself.
  *
- * @param interruptHandle the interrupt handle
- * @return                timestamp in microseconds since FPGA Initialization
+ * @param[in] interruptHandle the interrupt handle
+ * @param[out] status         Error status variable. 0 on success.
+ * @return timestamp in microseconds since FPGA Initialization
  */
 int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
                                          int32_t* status);
@@ -94,8 +69,9 @@
  * bottom 32 bits of the timestamp.  If your robot has been running for over 1
  * hour, you will need to fill in the upper 32 bits yourself.
  *
- * @param interruptHandle the interrupt handle
- * @return                timestamp in microseconds since FPGA Initialization
+ * @param[in] interruptHandle the interrupt handle
+ * @param[out] status         Error status variable. 0 on success.
+ * @return timestamp in microseconds since FPGA Initialization
  */
 int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
                                           int32_t* status);
@@ -103,10 +79,13 @@
 /**
  * Requests interrupts on a specific digital source.
  *
- * @param interruptHandle     the interrupt handle
- * @param digitalSourceHandle the digital source handle (either a
- * HAL_AnalogTriggerHandle of a HAL_DigitalHandle)
- * @param analogTriggerType   the trigger type if the source is an AnalogTrigger
+ * @param[in] interruptHandle     the interrupt handle
+ * @param[in] digitalSourceHandle the digital source handle (either a
+ *                                HAL_AnalogTriggerHandle or a
+ *                                HAL_DigitalHandle)
+ * @param[in] analogTriggerType   the trigger type if the source is an
+ *                                AnalogTrigger
+ * @param[out] status             Error status variable. 0 on success.
  */
 void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
                            HAL_Handle digitalSourceHandle,
@@ -114,41 +93,14 @@
                            int32_t* status);
 
 /**
- * Attaches an asynchronous interrupt handler to the interrupt.
- *
- * This interrupt gets called directly on the FPGA interrupt thread, so will
- * block other interrupts while running.
- *
- * @param interruptHandle the interrupt handle
- * @param handler         the handler function for the interrupt to call
- * @param param           a parameter to be passed to the handler
- */
-void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
-                                HAL_InterruptHandlerFunction handler,
-                                void* param, int32_t* status);
-
-/**
- * Attaches an asynchronous interrupt handler to the interrupt.
- *
- * This interrupt gets called on a thread specific to the interrupt, so will not
- * block other interrupts.
- *
- * @param interruptHandle the interrupt handle
- * @param handler         the handler function for the interrupt to call
- * @param param           a parameter to be passed to the handler
- */
-void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
-                                        HAL_InterruptHandlerFunction handler,
-                                        void* param, int32_t* status);
-
-/**
  * Sets the edges to trigger the interrupt on.
  *
  * Note that both edges triggered is a valid configuration.
  *
- * @param interruptHandle the interrupt handle
- * @param risingEdge      true for triggering on rising edge
- * @param fallingEdge     true for triggering on falling edge
+ * @param[in] interruptHandle the interrupt handle
+ * @param[in] risingEdge      true for triggering on rising edge
+ * @param[in] fallingEdge     true for triggering on falling edge
+ * @param[out] status         Error status variable. 0 on success.
  */
 void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
                                   HAL_Bool risingEdge, HAL_Bool fallingEdge,
@@ -159,7 +111,8 @@
  *
  * This will release both rising and falling waiters.
  *
- * @param interruptHandle the interrupt handle to release
+ * @param[in] interruptHandle the interrupt handle to release
+ * @param[out] status         Error status variable. 0 on success.
  */
 void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
                                  int32_t* status);
diff --git a/hal/src/main/native/include/hal/Main.h b/hal/src/main/native/include/hal/Main.h
index 097f819..712ad01 100644
--- a/hal/src/main/native/include/hal/Main.h
+++ b/hal/src/main/native/include/hal/Main.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/include/hal/Notifier.h b/hal/src/main/native/include/hal/Notifier.h
index 6b8e39f..96452f4 100644
--- a/hal/src/main/native/include/hal/Notifier.h
+++ b/hal/src/main/native/include/hal/Notifier.h
@@ -1,14 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <stdint.h>
 
+#include <wpi/nodiscard.h>
+
 #include "hal/Types.h"
 
 /**
@@ -27,15 +26,36 @@
  * A notifier is an FPGA controller timer that triggers at requested intervals
  * based on the FPGA time. This can be used to make precise control loops.
  *
+ * @param[out] status Error status variable. 0 on success.
  * @return the created notifier
  */
 HAL_NotifierHandle HAL_InitializeNotifier(int32_t* status);
 
 /**
+ * Sets the HAL notifier thread priority.
+ *
+ * The HAL notifier thread is responsible for managing the FPGA's notifier
+ * interrupt and waking up user's Notifiers when it's their time to run.
+ * Giving the HAL notifier thread real-time priority helps ensure the user's
+ * real-time Notifiers, if any, are notified to run in a timely manner.
+ *
+ * @param[in] realTime Set to true to set a real-time priority, false for
+ *                     standard priority.
+ * @param[in] priority Priority to set the thread to. For real-time, this is
+ *                     1-99 with 99 being highest. For non-real-time, this is
+ *                     forced to 0. See "man 7 sched" for more details.
+ * @param[out] status  Error status variable. 0 on success.
+ * @return True on success.
+ */
+HAL_Bool HAL_SetNotifierThreadPriority(HAL_Bool realTime, int32_t priority,
+                                       int32_t* status);
+
+/**
  * Sets the name of a notifier.
  *
- * @param notifierHandle the notifier handle
- * @param name name
+ * @param[in] notifierHandle the notifier handle
+ * @param[in] name name
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_SetNotifierName(HAL_NotifierHandle notifierHandle, const char* name,
                          int32_t* status);
@@ -45,7 +65,8 @@
  *
  * This will cause any call into HAL_WaitForNotifierAlarm to return.
  *
- * @param notifierHandle the notifier handle
+ * @param[in] notifierHandle the notifier handle
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_StopNotifier(HAL_NotifierHandle notifierHandle, int32_t* status);
 
@@ -54,7 +75,8 @@
  *
  * Note this also stops a notifier if it is already running.
  *
- * @param notifierHandle the notifier handle
+ * @param[in] notifierHandle the notifier handle
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_CleanNotifier(HAL_NotifierHandle notifierHandle, int32_t* status);
 
@@ -63,8 +85,9 @@
  *
  * Note that this time is an absolute time relative to HAL_GetFPGATime()
  *
- * @param notifierHandle the notifier handle
- * @param triggerTime    the updated trigger time
+ * @param[in] notifierHandle the notifier handle
+ * @param[in] triggerTime    the updated trigger time
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_UpdateNotifierAlarm(HAL_NotifierHandle notifierHandle,
                              uint64_t triggerTime, int32_t* status);
@@ -74,7 +97,8 @@
  *
  * This does not cause HAL_WaitForNotifierAlarm to return.
  *
- * @param notifierHandle the notifier handle
+ * @param[in] notifierHandle the notifier handle
+ * @param[out] status Error status variable. 0 on success.
  */
 void HAL_CancelNotifierAlarm(HAL_NotifierHandle notifierHandle,
                              int32_t* status);
@@ -83,11 +107,15 @@
  * Waits for the next alarm for the specific notifier.
  *
  * This is a blocking call until either the time elapses or HAL_StopNotifier
- * gets called.
+ * gets called. If the latter occurs, this function will return zero and any
+ * loops using this function should exit. Failing to do so can lead to
+ * use-after-frees.
  *
- * @param notifierHandle the notifier handle
- * @return               the FPGA time the notifier returned
+ * @param[in] notifierHandle the notifier handle
+ * @param[out] status        Error status variable. 0 on success.
+ * @return the FPGA time the notifier returned
  */
+WPI_NODISCARD
 uint64_t HAL_WaitForNotifierAlarm(HAL_NotifierHandle notifierHandle,
                                   int32_t* status);
 
diff --git a/hal/src/main/native/include/hal/PWM.h b/hal/src/main/native/include/hal/PWM.h
index 7267823..7fd125e 100644
--- a/hal/src/main/native/include/hal/PWM.h
+++ b/hal/src/main/native/include/hal/PWM.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,16 +21,21 @@
 /**
  * Initializes a PWM port.
  *
- * @param portHandle the port to initialize
- * @return           the created pwm handle
+ * @param[in] portHandle the port to initialize
+ * @param[in] allocationLocation  the location where the allocation is occuring
+ *                                (can be null)
+ * @param[out] status             Error status variable. 0 on success.
+ * @return the created pwm handle
  */
 HAL_DigitalHandle HAL_InitializePWMPort(HAL_PortHandle portHandle,
+                                        const char* allocationLocation,
                                         int32_t* status);
 
 /**
  * Frees a PWM port.
  *
- * @param pwmPortHandle the pwm handle
+ * @param[in] pwmPortHandle the pwm handle
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle, int32_t* status);
 
@@ -41,7 +43,7 @@
  * Checks if a pwm channel is valid.
  *
  * @param channel the channel to check
- * @return        true if the channel is valid, otherwise false
+ * @return true if the channel is valid, otherwise false
  */
 HAL_Bool HAL_CheckPWMChannel(int32_t channel);
 
@@ -50,12 +52,13 @@
  *
  * All values are in milliseconds.
  *
- * @param pwmPortHandle  the PWM handle
- * @param maxPwm         the maximum PWM value
- * @param deadbandMaxPwm the high range of the center deadband
- * @param centerPwm      the center PWM value
- * @param deadbandMinPwm the low range of the center deadband
- * @param minPwm         the minimum PWM value
+ * @param[in] pwmPortHandle  the PWM handle
+ * @param[in] maxPwm         the maximum PWM value
+ * @param[in] deadbandMaxPwm the high range of the center deadband
+ * @param[in] centerPwm      the center PWM value
+ * @param[in] deadbandMinPwm the low range of the center deadband
+ * @param[in] minPwm         the minimum PWM value
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_SetPWMConfig(HAL_DigitalHandle pwmPortHandle, double maxPwm,
                       double deadbandMaxPwm, double centerPwm,
@@ -69,12 +72,13 @@
  *
  * Values are in raw FPGA units.
  *
- * @param pwmPortHandle  the PWM handle
- * @param maxPwm         the maximum PWM value
- * @param deadbandMaxPwm the high range of the center deadband
- * @param centerPwm      the center PWM value
- * @param deadbandMinPwm the low range of the center deadband
- * @param minPwm         the minimum PWM value
+ * @param[in] pwmPortHandle  the PWM handle
+ * @param[in] maxPwm         the maximum PWM value
+ * @param[in] deadbandMaxPwm the high range of the center deadband
+ * @param[in] centerPwm      the center PWM value
+ * @param[in] deadbandMinPwm the low range of the center deadband
+ * @param[in] minPwm         the minimum PWM value
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_SetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t maxPwm,
                          int32_t deadbandMaxPwm, int32_t centerPwm,
@@ -87,12 +91,13 @@
  * Values are in raw FPGA units. These units have the potential to change for
  * any FPGA release.
  *
- * @param pwmPortHandle  the PWM handle
- * @param maxPwm         the maximum PWM value
- * @param deadbandMaxPwm the high range of the center deadband
- * @param centerPwm      the center PWM value
- * @param deadbandMinPwm the low range of the center deadband
- * @param minPwm         the minimum PWM value
+ * @param[in] pwmPortHandle  the PWM handle
+ * @param[in] maxPwm         the maximum PWM value
+ * @param[in] deadbandMaxPwm the high range of the center deadband
+ * @param[in] centerPwm      the center PWM value
+ * @param[in] deadbandMinPwm the low range of the center deadband
+ * @param[in] minPwm         the minimum PWM value
+ * @param[out] status        Error status variable. 0 on success.
  */
 void HAL_GetPWMConfigRaw(HAL_DigitalHandle pwmPortHandle, int32_t* maxPwm,
                          int32_t* deadbandMaxPwm, int32_t* centerPwm,
@@ -103,8 +108,9 @@
  * Sets if the FPGA should output the center value if the input value is within
  * the deadband.
  *
- * @param pwmPortHandle     the PWM handle
- * @param eliminateDeadband true to eliminate deadband, otherwise false
+ * @param[in] pwmPortHandle     the PWM handle
+ * @param[in] eliminateDeadband true to eliminate deadband, otherwise false
+ * @param[out] status           Error status variable. 0 on success.
  */
 void HAL_SetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
                                  HAL_Bool eliminateDeadband, int32_t* status);
@@ -112,8 +118,9 @@
 /**
  * Gets the current eliminate deadband value.
  *
- * @param pwmPortHandle the PWM handle
- * @return              true if set, otherwise false
+ * @param[in] pwmPortHandle the PWM handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return true if set, otherwise false
  */
 HAL_Bool HAL_GetPWMEliminateDeadband(HAL_DigitalHandle pwmPortHandle,
                                      int32_t* status);
@@ -124,8 +131,9 @@
  * The values are in raw FPGA units, and have the potential to change with any
  * FPGA release.
  *
- * @param pwmPortHandle the PWM handle
- * @param value         the PWM value to set
+ * @param[in] pwmPortHandle the PWM handle
+ * @param[in] value         the PWM value to set
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t value,
                    int32_t* status);
@@ -136,8 +144,9 @@
  * The values range from -1 to 1 and the period is controlled by the PWM Period
  * and MinHigh registers.
  *
- * @param pwmPortHandle the PWM handle
- * @param value         the scaled PWM value to set
+ * @param[in] pwmPortHandle the PWM handle
+ * @param[in] speed         the scaled PWM value to set
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetPWMSpeed(HAL_DigitalHandle pwmPortHandle, double speed,
                      int32_t* status);
@@ -148,8 +157,9 @@
  * The values range from 0 to 1 and the period is controlled by the PWM Period
  * and MinHigh registers.
  *
- * @param pwmPortHandle the PWM handle
- * @param value         the positional PWM value to set
+ * @param[in] pwmPortHandle the PWM handle
+ * @param[in] position      the positional PWM value to set
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetPWMPosition(HAL_DigitalHandle pwmPortHandle, double position,
                         int32_t* status);
@@ -161,7 +171,8 @@
  * from just setting a 0 speed, as this will actively stop all signaling on the
  * channel.
  *
- * @param pwmPortHandle the PWM handle.
+ * @param[in] pwmPortHandle the PWM handle.
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetPWMDisabled(HAL_DigitalHandle pwmPortHandle, int32_t* status);
 
@@ -171,8 +182,9 @@
  * The values are in raw FPGA units, and have the potential to change with any
  * FPGA release.
  *
- * @param pwmPortHandle the PWM handle
- * @return              the current raw PWM value
+ * @param[in] pwmPortHandle the PWM handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the current raw PWM value
  */
 int32_t HAL_GetPWMRaw(HAL_DigitalHandle pwmPortHandle, int32_t* status);
 
@@ -181,8 +193,9 @@
  *
  * The values range from -1 to 1.
  *
- * @param pwmPortHandle the PWM handle
- * @return              the current speed PWM value
+ * @param[in] pwmPortHandle the PWM handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the current speed PWM value
  */
 double HAL_GetPWMSpeed(HAL_DigitalHandle pwmPortHandle, int32_t* status);
 
@@ -191,23 +204,26 @@
  *
  * The values range from 0 to 1.
  *
- * @param pwmPortHandle the PWM handle
- * @return              the current positional PWM value
+ * @param[in] pwmPortHandle the PWM handle
+ * @param[out] status       Error status variable. 0 on success.
+ * @return the current positional PWM value
  */
 double HAL_GetPWMPosition(HAL_DigitalHandle pwmPortHandle, int32_t* status);
 
 /**
  * Forces a PWM signal to go to 0 temporarily.
  *
- * @param pwmPortHandle the PWM handle.
+ * @param[in] pwmPortHandle the PWM handle.
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_LatchPWMZero(HAL_DigitalHandle pwmPortHandle, int32_t* status);
 
 /**
  * Sets how how often the PWM signal is squelched, thus scaling the period.
  *
- * @param pwmPortHandle the PWM handle.
- * @param squelchMask   the 2-bit mask of outputs to squelch
+ * @param[in] pwmPortHandle the PWM handle.
+ * @param[in] squelchMask   the 2-bit mask of outputs to squelch
+ * @param[out] status       Error status variable. 0 on success.
  */
 void HAL_SetPWMPeriodScale(HAL_DigitalHandle pwmPortHandle, int32_t squelchMask,
                            int32_t* status);
@@ -215,6 +231,7 @@
 /**
  * Gets the loop timing of the PWM system.
  *
+ * @param[out] status Error status variable. 0 on success.
  * @return the loop time
  */
 int32_t HAL_GetPWMLoopTiming(int32_t* status);
@@ -224,6 +241,7 @@
  *
  * This time is relative to the FPGA time.
  *
+ * @param[out] status Error status variable. 0 on success.
  * @return the pwm cycle start time
  */
 uint64_t HAL_GetPWMCycleStartTime(int32_t* status);
diff --git a/hal/src/main/native/include/hal/Ports.h b/hal/src/main/native/include/hal/Ports.h
index 584bc4f..a212446 100644
--- a/hal/src/main/native/include/hal/Ports.h
+++ b/hal/src/main/native/include/hal/Ports.h
@@ -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.
 
 #pragma once
 
@@ -122,28 +119,56 @@
  *
  * @return the number of PCM modules
  */
-int32_t HAL_GetNumPCMModules(void);
+int32_t HAL_GetNumCTREPCMModules(void);
 
 /**
  * Gets the number of solenoid channels in the current system.
  *
  * @return the number of solenoid channels
  */
-int32_t HAL_GetNumSolenoidChannels(void);
+int32_t HAL_GetNumCTRESolenoidChannels(void);
 
 /**
  * Gets the number of PDP modules in the current system.
  *
  * @return the number of PDP modules
  */
-int32_t HAL_GetNumPDPModules(void);
+int32_t HAL_GetNumCTREPDPModules(void);
 
 /**
  * Gets the number of PDP channels in the current system.
  *
  * @return the number of PDP channels
  */
-int32_t HAL_GetNumPDPChannels(void);
+int32_t HAL_GetNumCTREPDPChannels(void);
+
+/**
+ * Gets the number of PDH modules in the current system.
+ *
+ * @return the number of PDH modules
+ */
+int32_t HAL_GetNumREVPDHModules(void);
+
+/**
+ * Gets the number of PDH channels in the current system.
+ *
+ * @return the number of PDH channels
+ */
+int32_t HAL_GetNumREVPDHChannels(void);
+
+/**
+ * Gets the number of PH modules in the current system.
+ *
+ * @return the number of PH modules
+ */
+int32_t HAL_GetNumREVPHModules(void);
+
+/**
+ * Gets the number of PH channels in the current system.
+ *
+ * @return the number of PH channels
+ */
+int32_t HAL_GetNumREVPHChannels(void);
 
 /**
  * Gets the number of duty cycle inputs in the current system.
diff --git a/hal/src/main/native/include/hal/Power.h b/hal/src/main/native/include/hal/Power.h
index 7ac7991..2bd983a 100644
--- a/hal/src/main/native/include/hal/Power.h
+++ b/hal/src/main/native/include/hal/Power.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
 
@@ -24,6 +21,7 @@
 /**
  * Gets the roboRIO input voltage.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the input voltage (volts)
  */
 double HAL_GetVinVoltage(int32_t* status);
@@ -31,6 +29,7 @@
 /**
  * Gets the roboRIO input current.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the input current (amps)
  */
 double HAL_GetVinCurrent(int32_t* status);
@@ -38,6 +37,7 @@
 /**
  * Gets the 6V rail voltage.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the 6V rail voltage (volts)
  */
 double HAL_GetUserVoltage6V(int32_t* status);
@@ -45,6 +45,7 @@
 /**
  * Gets the 6V rail current.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the 6V rail current (amps)
  */
 double HAL_GetUserCurrent6V(int32_t* status);
@@ -52,6 +53,7 @@
 /**
  * Gets the active state of the 6V rail.
  *
+ * @param[out] status the error code, or 0 for success
  * @return true if the rail is active, otherwise false
  */
 HAL_Bool HAL_GetUserActive6V(int32_t* status);
@@ -59,6 +61,7 @@
 /**
  * Gets the fault count for the 6V rail.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the number of 6V fault counts
  */
 int32_t HAL_GetUserCurrentFaults6V(int32_t* status);
@@ -66,6 +69,7 @@
 /**
  * Gets the 5V rail voltage.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the 5V rail voltage (volts)
  */
 double HAL_GetUserVoltage5V(int32_t* status);
@@ -73,6 +77,7 @@
 /**
  * Gets the 5V rail current.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the 5V rail current (amps)
  */
 double HAL_GetUserCurrent5V(int32_t* status);
@@ -80,6 +85,7 @@
 /**
  * Gets the active state of the 5V rail.
  *
+ * @param[out] status the error code, or 0 for success
  * @return true if the rail is active, otherwise false
  */
 HAL_Bool HAL_GetUserActive5V(int32_t* status);
@@ -87,6 +93,7 @@
 /**
  * Gets the fault count for the 5V rail.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the number of 5V fault counts
  */
 int32_t HAL_GetUserCurrentFaults5V(int32_t* status);
@@ -94,6 +101,7 @@
 /**
  * Gets the 3V3 rail voltage.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the 3V3 rail voltage (volts)
  */
 double HAL_GetUserVoltage3V3(int32_t* status);
@@ -101,6 +109,7 @@
 /**
  * Gets the 3V3 rail current.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the 3V3 rail current (amps)
  */
 double HAL_GetUserCurrent3V3(int32_t* status);
@@ -108,6 +117,7 @@
 /**
  * Gets the active state of the 3V3 rail.
  *
+ * @param[out] status the error code, or 0 for success
  * @return true if the rail is active, otherwise false
  */
 HAL_Bool HAL_GetUserActive3V3(int32_t* status);
@@ -115,9 +125,30 @@
 /**
  * Gets the fault count for the 3V3 rail.
  *
+ * @param[out] status the error code, or 0 for success
  * @return the number of 3V3 fault counts
  */
 int32_t HAL_GetUserCurrentFaults3V3(int32_t* status);
+
+/**
+ * Get the current brownout voltage setting.
+ *
+ * @param[out] status the error code, or 0 for success
+ * @return The brownout voltage
+ */
+double HAL_GetBrownoutVoltage(int32_t* status);
+
+/**
+ * Set the voltage the roboRIO will brownout and disable all outputs.
+ *
+ * Note that this only does anything on the roboRIO 2.
+ * On the roboRIO it is a no-op.
+ *
+ * @param[in] voltage The brownout voltage
+ * @param[out] status the error code, or 0 for success
+ */
+void HAL_SetBrownoutVoltage(double voltage, int32_t* status);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/hal/src/main/native/include/hal/PowerDistribution.h b/hal/src/main/native/include/hal/PowerDistribution.h
new file mode 100644
index 0000000..fabb8b7
--- /dev/null
+++ b/hal/src/main/native/include/hal/PowerDistribution.h
@@ -0,0 +1,224 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_pd Power Distribution Functions
+ * @ingroup hal_capi
+ * Functions to control Power Distribution devices.
+ * @{
+ */
+
+// clang-format off
+/**
+ * The acceptable accelerometer ranges.
+ */
+HAL_ENUM(HAL_PowerDistributionType) {
+  HAL_PowerDistributionType_kAutomatic = 0,
+  HAL_PowerDistributionType_kCTRE = 1,
+  HAL_PowerDistributionType_kRev = 2,
+};
+// clang-format on
+
+#define HAL_DEFAULT_POWER_DISTRIBUTION_MODULE -1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a Power Distribution Panel.
+ *
+ * @param[in] moduleNumber       the module number to initialize
+ * @param[in] type               the type of module to intialize
+ * @param[in] allocationLocation the location where the allocation is occuring
+ * @param[out] status            Error status variable. 0 on success.
+ * @return the created PowerDistribution
+ */
+HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
+    int32_t moduleNumber, HAL_PowerDistributionType type,
+    const char* allocationLocation, int32_t* status);
+
+/**
+ * Gets the module number for a specific handle.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the module number
+ */
+int32_t HAL_GetPowerDistributionModuleNumber(HAL_PowerDistributionHandle handle,
+                                             int32_t* status);
+
+/**
+ * Cleans a PowerDistribution module.
+ *
+ * @param handle the module handle
+ */
+void HAL_CleanPowerDistribution(HAL_PowerDistributionHandle handle);
+
+/**
+ * Checks if a PowerDistribution channel is valid.
+ *
+ * @param handle  the module handle
+ * @param channel the channel to check
+ * @return true if the channel is valid, otherwise false
+ */
+HAL_Bool HAL_CheckPowerDistributionChannel(HAL_PowerDistributionHandle handle,
+                                           int32_t channel);
+
+/**
+ * Checks if a PowerDistribution module is valid.
+ *
+ * @param module the module to check
+ * @param type   the type of module
+ * @return true if the module is valid, otherwise false
+ */
+HAL_Bool HAL_CheckPowerDistributionModule(int32_t module,
+                                          HAL_PowerDistributionType type);
+
+/**
+ * Gets the type of PowerDistribution module.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the type of module
+ */
+HAL_PowerDistributionType HAL_GetPowerDistributionType(
+    HAL_PowerDistributionHandle handle, int32_t* status);
+
+/**
+ * Gets the number of channels for this handle.
+ *
+ * @param[in] handle the handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return number of channels
+ */
+int32_t HAL_GetPowerDistributionNumChannels(HAL_PowerDistributionHandle handle,
+                                            int32_t* status);
+
+/**
+ * Gets the temperature of the PowerDistribution.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the module temperature (celsius)
+ */
+double HAL_GetPowerDistributionTemperature(HAL_PowerDistributionHandle handle,
+                                           int32_t* status);
+
+/**
+ * Gets the PowerDistribution input voltage.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the input voltage (volts)
+ */
+double HAL_GetPowerDistributionVoltage(HAL_PowerDistributionHandle handle,
+                                       int32_t* status);
+
+/**
+ * Gets the current of a specific PowerDistribution channel.
+ *
+ * @param[in] handle   the module handle
+ * @param[in] channel  the channel
+ * @param[out] status  Error status variable. 0 on success.
+ * @return the channel current (amps)
+ */
+double HAL_GetPowerDistributionChannelCurrent(
+    HAL_PowerDistributionHandle handle, int32_t channel, int32_t* status);
+
+/**
+ * Gets the current of all 24 channels on the PowerDistribution.
+ *
+ * The array must be large enough to hold all channels.
+ *
+ * @param[in] handle         the module handle
+ * @param[out] currents      the currents
+ * @param[in] currentsLength the length of the currents array
+ * @param[out] status        Error status variable. 0 on success.
+ */
+void HAL_GetPowerDistributionAllChannelCurrents(
+    HAL_PowerDistributionHandle handle, double* currents,
+    int32_t currentsLength, int32_t* status);
+
+/**
+ * Gets the total current of the PowerDistribution.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the total current (amps)
+ */
+double HAL_GetPowerDistributionTotalCurrent(HAL_PowerDistributionHandle handle,
+                                            int32_t* status);
+
+/**
+ * Gets the total power of the PowerDistribution.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the total power (watts)
+ */
+double HAL_GetPowerDistributionTotalPower(HAL_PowerDistributionHandle handle,
+                                          int32_t* status);
+
+/**
+ * Gets the total energy of the PowerDistribution.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ * @return the total energy (joules)
+ */
+double HAL_GetPowerDistributionTotalEnergy(HAL_PowerDistributionHandle handle,
+                                           int32_t* status);
+
+/**
+ * Resets the PowerDistribution accumulated energy.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ */
+void HAL_ResetPowerDistributionTotalEnergy(HAL_PowerDistributionHandle handle,
+                                           int32_t* status);
+
+/**
+ * Clears any PowerDistribution sticky faults.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ */
+void HAL_ClearPowerDistributionStickyFaults(HAL_PowerDistributionHandle handle,
+                                            int32_t* status);
+
+/**
+ * Power on/off switchable channel.
+ *
+ * This is a REV PDH-specific function. This function will no-op on CTRE PDP.
+ *
+ * @param[in] handle the module handle
+ * @param[in] enabled true to turn on switchable channel
+ * @param[out] status Error status variable. 0 on success.
+ */
+void HAL_SetPowerDistributionSwitchableChannel(
+    HAL_PowerDistributionHandle handle, HAL_Bool enabled, int32_t* status);
+
+/**
+ * Returns true if switchable channel is powered on.
+ *
+ * This is a REV PDH-specific function. This function will no-op on CTRE PDP.
+ *
+ * @param[in] handle the module handle
+ * @param[out] status Error status variable. 0 on success.
+ */
+HAL_Bool HAL_GetPowerDistributionSwitchableChannel(
+    HAL_PowerDistributionHandle handle, int32_t* status);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/REVPH.h b/hal/src/main/native/include/hal/REVPH.h
new file mode 100644
index 0000000..0cab15e
--- /dev/null
+++ b/hal/src/main/native/include/hal/REVPH.h
@@ -0,0 +1,49 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include <stdint.h>
+
+#include "hal/Types.h"
+
+/**
+ * @defgroup hal_rev_ph REV PH Functions
+ * @ingroup hal_capi
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
+                                    const char* allocationLocation,
+                                    int32_t* status);
+
+void HAL_FreeREVPH(HAL_REVPHHandle handle);
+
+HAL_Bool HAL_CheckREVPHSolenoidChannel(int32_t channel);
+HAL_Bool HAL_CheckREVPHModuleNumber(int32_t module);
+
+HAL_Bool HAL_GetREVPHCompressor(HAL_REVPHHandle handle, int32_t* status);
+void HAL_SetREVPHClosedLoopControl(HAL_REVPHHandle handle, HAL_Bool enabled,
+                                   int32_t* status);
+HAL_Bool HAL_GetREVPHClosedLoopControl(HAL_REVPHHandle handle, int32_t* status);
+HAL_Bool HAL_GetREVPHPressureSwitch(HAL_REVPHHandle handle, int32_t* status);
+double HAL_GetREVPHCompressorCurrent(HAL_REVPHHandle handle, int32_t* status);
+double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
+                                  int32_t* status);
+
+int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status);
+void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
+                           int32_t* status);
+
+void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
+                          int32_t* status);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
diff --git a/hal/src/main/native/include/hal/Relay.h b/hal/src/main/native/include/hal/Relay.h
index 281aad6..7d711b2 100644
--- a/hal/src/main/native/include/hal/Relay.h
+++ b/hal/src/main/native/include/hal/Relay.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
 
@@ -27,11 +24,16 @@
  * Note this call will only initialize either the forward or reverse port of the
  * relay. If you need both, you will need to initialize 2 relays.
  *
- * @param portHandle the port handle to initialize
- * @param fwd        true for the forward port, false for the reverse port
- * @return           the created relay handle
+ * @param[in] portHandle         the port handle to initialize
+ * @param[in] fwd                true for the forward port, false for the
+ *                               reverse port
+ * @param[in] allocationLocation the location where the allocation is occuring
+ *                               (can be null)
+ * @param[out] status            Error status variable. 0 on success.
+ * @return the created relay handle
  */
 HAL_RelayHandle HAL_InitializeRelayPort(HAL_PortHandle portHandle, HAL_Bool fwd,
+                                        const char* allocationLocation,
                                         int32_t* status);
 
 /**
@@ -45,15 +47,16 @@
  * Checks if a relay channel is valid.
  *
  * @param channel the channel to check
- * @return        true if the channel is valid, otherwise false
+ * @return true if the channel is valid, otherwise false
  */
 HAL_Bool HAL_CheckRelayChannel(int32_t channel);
 
 /**
  * Sets the state of a relay output.
  *
- * @param relayPortHandle the relay handle
- * @param on              true for on, false for off
+ * @param[in] relayPortHandle the relay handle
+ * @param[in] on              true for on, false for off
+ * @param[out] status         Error status variable. 0 on success.
  */
 void HAL_SetRelay(HAL_RelayHandle relayPortHandle, HAL_Bool on,
                   int32_t* status);
@@ -61,8 +64,9 @@
 /**
  * Gets the current state of the relay channel.
  *
- * @param relayPortHandle the relay handle
- * @return                true for on, false for off
+ * @param[in] relayPortHandle the relay handle
+ * @param[out] status         Error status variable. 0 on success.
+ * @return true for on, false for off
  */
 HAL_Bool HAL_GetRelay(HAL_RelayHandle relayPortHandle, int32_t* status);
 #ifdef __cplusplus
diff --git a/hal/src/main/native/include/hal/SPI.h b/hal/src/main/native/include/hal/SPI.h
index abee379..84cec5d 100644
--- a/hal/src/main/native/include/hal/SPI.h
+++ b/hal/src/main/native/include/hal/SPI.h
@@ -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.
 
 #pragma once
 
@@ -28,7 +25,9 @@
  *
  * If opening the MXP port, also sets up the channel functions appropriately.
  *
- * @param port The number of the port to use. 0-3 for Onboard CS0-CS3, 4 for MXP
+ * @param[in] port    The number of the port to use. 0-3 for Onboard CS0-CS3, 4
+ *                    for MXP
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status);
 
@@ -39,11 +38,11 @@
  * over each transaction.
  *
  * @param port         The number of the port to use. 0-3 for Onboard CS0-CS2, 4
- * for MXP
+ *                     for MXP
  * @param dataToSend   Buffer of data to send as part of the transaction.
  * @param dataReceived Buffer to read data into.
  * @param size         Number of bytes to transfer. [0..7]
- * @return             Number of bytes transferred, -1 for error
+ * @return Number of bytes transferred, -1 for error
  */
 int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend,
                            uint8_t* dataReceived, int32_t size);
@@ -53,11 +52,11 @@
  *
  * Writes to a device and wait until the transaction is complete.
  *
- * @param port      The number of the port to use. 0-3 for Onboard CS0-CS2, 4
- * for MXP
- * @param datToSend The data to write to the register on the device.
- * @param sendSize  The number of bytes to be written
- * @return          The number of bytes written. -1 for an error
+ * @param port       The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ *                   for MXP
+ * @param dataToSend The data to write to the register on the device.
+ * @param sendSize   The number of bytes to be written
+ * @return The number of bytes written. -1 for an error
  */
 int32_t HAL_WriteSPI(HAL_SPIPort port, const uint8_t* dataToSend,
                      int32_t sendSize);
@@ -71,11 +70,11 @@
  * begin returning data.
  *
  * @param port   The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP
+ *               MXP
  * @param buffer A pointer to the array of bytes to store the data read from the
- * device.
+ *               device.
  * @param count  The number of bytes to read in the transaction. [1..7]
- * @return       Number of bytes read. -1 for error.
+ * @return Number of bytes read. -1 for error.
  */
 int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count);
 
@@ -90,7 +89,7 @@
  * Sets the clock speed for the SPI bus.
  *
  * @param port  The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP
+ *              MXP
  * @param speed The speed in Hz (0-1MHz)
  */
 void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed);
@@ -99,12 +98,12 @@
  * Sets the SPI options.
  *
  * @param port             The number of the port to use. 0-3 for Onboard
- * CS0-CS2, 4 for MXP
+ *                         CS0-CS2, 4 for MXP
  * @param msbFirst         True to write the MSB first, False for LSB first
  * @param sampleOnTrailing True to sample on the trailing edge, False to sample
- * on the leading edge
+ *                         on the leading edge
  * @param clkIdleHigh      True to set the clock to active low, False to set the
- * clock active high
+ *                         clock active high
  */
 void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst,
                     HAL_Bool sampleOnTrailing, HAL_Bool clkIdleHigh);
@@ -112,14 +111,18 @@
 /**
  * Sets the CS Active high for a SPI port.
  *
- * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
+ * @param[in] port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
+ *                 MXP
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSPIChipSelectActiveHigh(HAL_SPIPort port, int32_t* status);
 
 /**
  * Sets the CS Active low for a SPI port.
  *
- * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
+ * @param[in] port    The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ *                    for MXP
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSPIChipSelectActiveLow(HAL_SPIPort port, int32_t* status);
 
@@ -127,8 +130,8 @@
  * Gets the stored handle for a SPI port.
  *
  * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for MXP
- * @return     The stored handle for the SPI port. 0 represents no stored
- * handle.
+ * @return The stored handle for the SPI port. 0 represents no stored
+ *         handle.
  */
 int32_t HAL_GetSPIHandle(HAL_SPIPort port);
 
@@ -136,7 +139,7 @@
  * Sets the stored handle for a SPI port.
  *
  * @param port   The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP.
+ *               MXP.
  * @param handle The value of the handle for the port.
  */
 void HAL_SetSPIHandle(HAL_SPIPort port, int32_t handle);
@@ -144,26 +147,29 @@
 /**
  * Initializes the SPI automatic accumulator.
  *
- * @param port       The number of the port to use. 0-3 for Onboard CS0-CS2, 4
- * for MXP.
- * @param bufferSize The accumulator buffer size.
+ * @param[in] port       The number of the port to use. 0-3 for Onboard CS0-CS2,
+ *                       4 for MXP.
+ * @param[in] bufferSize The accumulator buffer size.
+ * @param[out] status    the error code, or 0 for success
  */
 void HAL_InitSPIAuto(HAL_SPIPort port, int32_t bufferSize, int32_t* status);
 
 /**
  * Frees an SPI automatic accumulator.
  *
- * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP.
+ * @param[in] port    The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ *                    for MXP.
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_FreeSPIAuto(HAL_SPIPort port, int32_t* status);
 
 /**
  * Sets the period for automatic SPI accumulation.
  *
- * @param port   The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP.
- * @param period The accumlation period (seconds).
+ * @param[in] port    The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ *                    for MXP.
+ * @param[in] period  The accumlation period (seconds).
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_StartSPIAutoRate(HAL_SPIPort port, double period, int32_t* status);
 
@@ -173,14 +179,15 @@
  * Note that triggering on both rising and falling edges is a valid
  * configuration.
  *
- * @param port                The number of the port to use. 0-3 for Onboard
- * CS0-CS2, 4 for MXP.
- * @param digitalSourceHandle The trigger source to use (Either
- * HAL_AnalogTriggerHandle or HAL_DigitalHandle).
- * @param analogTriggerType   The analog trigger type, if the source is an
- * analog trigger.
- * @param triggerRising       Trigger on the rising edge if true.
- * @param triggerFalling      Trigger on the falling edge if true.
+ * @param[in] port                The number of the port to use. 0-3 for Onboard
+ *                                CS0-CS2, 4 for MXP.
+ * @param[in] digitalSourceHandle The trigger source to use (Either
+ *                                HAL_AnalogTriggerHandle or HAL_DigitalHandle).
+ * @param[in] analogTriggerType   The analog trigger type, if the source is an
+ *                                analog trigger.
+ * @param[in] triggerRising       Trigger on the rising edge if true.
+ * @param[in] triggerFalling      Trigger on the falling edge if true.
+ * @param[out] status             the error code, or 0 for success
  */
 void HAL_StartSPIAutoTrigger(HAL_SPIPort port, HAL_Handle digitalSourceHandle,
                              HAL_AnalogTriggerType analogTriggerType,
@@ -190,20 +197,22 @@
 /**
  * Stops an automatic SPI accumlation.
  *
- * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP.
+ * @param[in] port    The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ *                    for MXP.
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_StopSPIAuto(HAL_SPIPort port, int32_t* status);
 
 /**
  * Sets the data to be transmitted to the device to initiate a read.
  *
- * @param port       The number of the port to use. 0-3 for Onboard CS0-CS2, 4
- * for MXP.
- * @param dataToSend Pointer to the data to send (Gets copied for continue use,
- * so no need to keep alive).
- * @param dataSize   The length of the data to send.
- * @param zeroSize   The number of zeros to send after the data.
+ * @param[in] port       The number of the port to use. 0-3 for Onboard CS0-CS2,
+ *                       4 for MXP.
+ * @param[in] dataToSend Pointer to the data to send (Gets copied for continue
+ *                       use, so no need to keep alive).
+ * @param[in] dataSize   The length of the data to send.
+ * @param[in] zeroSize   The number of zeros to send after the data.
+ * @param[out] status    the error code, or 0 for success
  */
 void HAL_SetSPIAutoTransmitData(HAL_SPIPort port, const uint8_t* dataToSend,
                                 int32_t dataSize, int32_t zeroSize,
@@ -212,8 +221,9 @@
 /**
  * Immediately forces an SPI read to happen.
  *
- * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP.
+ * @param[in] port    The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ *                    for MXP.
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_ForceSPIAutoRead(HAL_SPIPort port, int32_t* status);
 
@@ -224,12 +234,13 @@
  * sequence is the same as the combined dataSize + zeroSize set in
  * HAL_SetSPIAutoTransmitData.
  *
- * @param port      The number of the port to use. 0-3 for Onboard CS0-CS2, 4
- * for MXP.
- * @param buffer    The buffer to store the data into.
- * @param numToRead The number of words to read.
- * @param timeout   The read timeout (in seconds).
- * @return          The number of words actually read.
+ * @param[in] port      The number of the port to use. 0-3 for Onboard CS0-CS2,
+ *                      4 for MXP.
+ * @param[out] buffer   The buffer to store the data into.
+ * @param[in] numToRead The number of words to read.
+ * @param[in] timeout   The read timeout (in seconds).
+ * @param[out] status   the error code, or 0 for success
+ * @return The number of words actually read.
  */
 int32_t HAL_ReadSPIAutoReceivedData(HAL_SPIPort port, uint32_t* buffer,
                                     int32_t numToRead, double timeout,
@@ -238,20 +249,23 @@
 /**
  * Gets the count of how many SPI accumulations have been missed.
  *
- * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP.
- * @return     The number of missed accumulations.
+ * @param[in] port    The number of the port to use. 0-3 for Onboard CS0-CS2, 4
+ *                    for MXP.
+ * @param[out] status the error code, or 0 for success
+ * @return The number of missed accumulations.
  */
 int32_t HAL_GetSPIAutoDroppedCount(HAL_SPIPort port, int32_t* status);
 
 /**
  * Configure the Auto SPI Stall time between reads.
  *
- * @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
- * MXP.
- * @param csToSclkTicks the number of ticks to wait before asserting the cs pin
- * @param stallTicks the number of ticks to stall for
- * @param pow2BytesPerRead the number of bytes to read before stalling
+ * @param[in] port             The number of the port to use. 0-3 for Onboard
+ *                             CS0-CS2, 4 for MXP.
+ * @param[in] csToSclkTicks    the number of ticks to wait before asserting the
+ *                             cs pin
+ * @param[in] stallTicks       the number of ticks to stall for
+ * @param[in] pow2BytesPerRead the number of bytes to read before stalling
+ * @param[out] status          the error code, or 0 for success
  */
 void HAL_ConfigureSPIAutoStall(HAL_SPIPort port, int32_t csToSclkTicks,
                                int32_t stallTicks, int32_t pow2BytesPerRead,
diff --git a/hal/src/main/native/include/hal/SPITypes.h b/hal/src/main/native/include/hal/SPITypes.h
index 170bd27..de66226 100644
--- a/hal/src/main/native/include/hal/SPITypes.h
+++ b/hal/src/main/native/include/hal/SPITypes.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
diff --git a/hal/src/main/native/include/hal/SerialPort.h b/hal/src/main/native/include/hal/SerialPort.h
index 226a2cb..cd6140e 100644
--- a/hal/src/main/native/include/hal/SerialPort.h
+++ b/hal/src/main/native/include/hal/SerialPort.h
@@ -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.
 
 #pragma once
 
@@ -36,7 +33,8 @@
  * The channels are either the onboard RS232, the mxp uart, or 2 USB ports. The
  * top port is USB1, the bottom port is USB2.
  *
- * @param port the serial port to initialize
+ * @param[in] port the serial port to initialize
+ * @param[out] status the error code, or 0 for success
  */
 HAL_SerialPortHandle HAL_InitializeSerialPort(HAL_SerialPort port,
                                               int32_t* status);
@@ -47,8 +45,9 @@
  * This name is the /dev name for a specific port.
  * Note these are not always consistent between roboRIO reboots.
  *
- * @param port     the serial port to initialize
- * @param portName the dev port name
+ * @param[in] port     the serial port to initialize
+ * @param[in] portName the dev port name
+ * @param[out] status  the error code, or 0 for success
  */
 HAL_SerialPortHandle HAL_InitializeSerialPortDirect(HAL_SerialPort port,
                                                     const char* portName,
@@ -57,8 +56,9 @@
 /**
  * Gets the raw serial port file descriptor from a handle.
  *
- * @param handle the serial port handle
- * @return       the raw port descriptor
+ * @param[in] handle the serial port handle
+ * @param[out] status the error code, or 0 for success
+ * @return the raw port descriptor
  */
 int HAL_GetSerialFD(HAL_SerialPortHandle handle, int32_t* status);
 
@@ -67,8 +67,9 @@
  *
  * Any value between 0 and 0xFFFFFFFF may be used. Default is 9600.
  *
- * @param handle the serial port handle
- * @param baud   the baud rate to set
+ * @param[in] handle  the serial port handle
+ * @param[in] baud    the baud rate to set
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSerialBaudRate(HAL_SerialPortHandle handle, int32_t baud,
                            int32_t* status);
@@ -78,8 +79,9 @@
  *
  * Defaults to 8.
  *
- * @param handle the serial port handle
- * @param bits   the number of data bits (5-8)
+ * @param[in] handle  the serial port handle
+ * @param[in] bits    the number of data bits (5-8)
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSerialDataBits(HAL_SerialPortHandle handle, int32_t bits,
                            int32_t* status);
@@ -94,8 +96,9 @@
  *   3: Mark - Means exists and always 1
  *   4: Space - Means exists and always 0
  *
- * @param handle the serial port handle
- * @param parity the parity bit mode (see remarks for valid values)
+ * @param[in] handle  the serial port handle
+ * @param[in] parity  the parity bit mode (see remarks for valid values)
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSerialParity(HAL_SerialPortHandle handle, int32_t parity,
                          int32_t* status);
@@ -108,8 +111,9 @@
  *   15: One and a half stop bits
  *   20: Two stop bits
  *
- * @param handle   the serial port handle
- * @param stopBits the stop bit value (see remarks for valid values)
+ * @param[in] handle    the serial port handle
+ * @param[in] stopBits  the stop bit value (see remarks for valid values)
+ * @param[out] status   the error code, or 0 for success
  */
 void HAL_SetSerialStopBits(HAL_SerialPortHandle handle, int32_t stopBits,
                            int32_t* status);
@@ -121,8 +125,9 @@
  *   1: Flush on access
  *   2: Flush when full (default)
  *
- * @param handle the serial port handle
- * @param mode   the mode to set (see remarks for valid values)
+ * @param[in] handle  the serial port handle
+ * @param[in] mode    the mode to set (see remarks for valid values)
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSerialWriteMode(HAL_SerialPortHandle handle, int32_t mode,
                             int32_t* status);
@@ -136,8 +141,9 @@
  *   2: RTS-CTS
  *   3: DTR-DSR
  *
- * @param handle the serial port handle
- * @param flow   the mode to set (see remarks for valid values)
+ * @param[in] handle  the serial port handle
+ * @param[in] flow    the mode to set (see remarks for valid values)
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSerialFlowControl(HAL_SerialPortHandle handle, int32_t flow,
                               int32_t* status);
@@ -145,8 +151,9 @@
 /**
  * Sets the minimum serial read timeout of a port.
  *
- * @param handle  the serial port handle
- * @param timeout the timeout in milliseconds
+ * @param[in] handle   the serial port handle
+ * @param[in] timeout  the timeout in milliseconds
+ * @param[out] status  the error code, or 0 for success
  */
 void HAL_SetSerialTimeout(HAL_SerialPortHandle handle, double timeout,
                           int32_t* status);
@@ -156,8 +163,9 @@
  *
  * By default this is disabled.
  *
- * @param handle     the serial port handle
- * @param terminator the termination character to set
+ * @param[in] handle      the serial port handle
+ * @param[in] terminator  the termination character to set
+ * @param[out] status     the error code, or 0 for success
  */
 void HAL_EnableSerialTermination(HAL_SerialPortHandle handle, char terminator,
                                  int32_t* status);
@@ -165,15 +173,17 @@
 /**
  * Disables a termination character for reads.
  *
- * @param handle the serial port handle
+ * @param[in] handle  the serial port handle
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_DisableSerialTermination(HAL_SerialPortHandle handle, int32_t* status);
 
 /**
  * Sets the size of the read buffer.
  *
- * @param handle the serial port handle
- * @param size   the read buffer size
+ * @param[in] handle  the serial port handle
+ * @param[in] size    the read buffer size
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSerialReadBufferSize(HAL_SerialPortHandle handle, int32_t size,
                                  int32_t* status);
@@ -181,8 +191,9 @@
 /**
  * Sets the size of the write buffer.
  *
- * @param handle the serial port handle
- * @param size   the write buffer size
+ * @param[in] handle  the serial port handle
+ * @param[in] size    the write buffer size
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_SetSerialWriteBufferSize(HAL_SerialPortHandle handle, int32_t size,
                                   int32_t* status);
@@ -190,8 +201,9 @@
 /**
  * Gets the number of bytes currently in the read buffer.
  *
- * @param handle the serial port handle
- * @return       the number of bytes in the read buffer
+ * @param[in] handle  the serial port handle
+ * @param[out] status the error code, or 0 for success
+ * @return the number of bytes in the read buffer
  */
 int32_t HAL_GetSerialBytesReceived(HAL_SerialPortHandle handle,
                                    int32_t* status);
@@ -202,9 +214,11 @@
  * Will wait for either timeout (if set), the termination char (if set), or the
  * count to be full. Whichever one comes first.
  *
- * @param handle the serial port handle
- * @param count  the number of bytes maximum to read
- * @return       the number of bytes actually read
+ * @param[in] handle  the serial port handle
+ * @param[out] buffer the buffer in which to store bytes read
+ * @param[in] count   the number of bytes maximum to read
+ * @param[out] status the error code, or 0 for success
+ * @return the number of bytes actually read
  */
 int32_t HAL_ReadSerial(HAL_SerialPortHandle handle, char* buffer, int32_t count,
                        int32_t* status);
@@ -212,10 +226,11 @@
 /**
  * Writes data to the serial port.
  *
- * @param handle the serial port handle
- * @param buffer the buffer to write
- * @param count  the number of bytes to write from the buffer
- * @return       the number of bytes actually written
+ * @param[in] handle  the serial port handle
+ * @param[in] buffer  the buffer to write
+ * @param[in] count   the number of bytes to write from the buffer
+ * @param[out] status the error code, or 0 for success
+ * @return the number of bytes actually written
  */
 int32_t HAL_WriteSerial(HAL_SerialPortHandle handle, const char* buffer,
                         int32_t count, int32_t* status);
@@ -223,21 +238,24 @@
 /**
  * Flushes the serial write buffer out to the port.
  *
- * @param handle the serial port handle
+ * @param[in] handle  the serial port handle
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_FlushSerial(HAL_SerialPortHandle handle, int32_t* status);
 
 /**
  * Clears the receive buffer of the serial port.
  *
- * @param handle the serial port handle
+ * @param[in] handle  the serial port handle
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_ClearSerial(HAL_SerialPortHandle handle, int32_t* status);
 
 /**
  * Closes a serial port.
  *
- * @param handle the serial port handle to close
+ * @param[in] handle  the serial port handle to close
+ * @param[out] status the error code, or 0 for success
  */
 void HAL_CloseSerial(HAL_SerialPortHandle handle, int32_t* status);
 #ifdef __cplusplus
diff --git a/hal/src/main/native/include/hal/SimDevice.h b/hal/src/main/native/include/hal/SimDevice.h
index ff4c12e..7c0cf2d 100644
--- a/hal/src/main/native/include/hal/SimDevice.h
+++ b/hal/src/main/native/include/hal/SimDevice.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2019-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -12,7 +9,7 @@
 #ifdef __cplusplus
 #include <initializer_list>
 
-#include <wpi/ArrayRef.h>
+#include <wpi/span.h>
 #endif
 
 #include "hal/Types.h"
@@ -30,6 +27,17 @@
  * @{
  */
 
+/**
+ * Direction of a simulated value (from the perspective of user code).
+ */
+// clang-format off
+HAL_ENUM(HAL_SimValueDirection) {
+  HAL_SimValueInput = 0,  /**< input to user code from the simulator */
+  HAL_SimValueOutput,     /**< output from user code to the simulator */
+  HAL_SimValueBidir       /**< bidirectional between user code and simulator */
+};
+// clang-format on
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -67,26 +75,66 @@
  *
  * @param device simulated device handle
  * @param name value name
- * @param readonly if the value should not be written from simulation side
+ * @param direction input/output/bidir (from perspective of user code)
  * @param initialValue initial value
  * @return simulated value handle
  */
 HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
-                                      const char* name, HAL_Bool readonly,
+                                      const char* name, int32_t direction,
                                       const struct HAL_Value* initialValue);
 
 #ifdef __cplusplus
 extern "C++" {
 inline HAL_SimValueHandle HAL_CreateSimValue(HAL_SimDeviceHandle device,
                                              const char* name,
-                                             HAL_Bool readonly,
+                                             int32_t direction,
                                              const HAL_Value& initialValue) {
-  return HAL_CreateSimValue(device, name, readonly, &initialValue);
+  return HAL_CreateSimValue(device, name, direction, &initialValue);
 }
 }  // extern "C++"
 #endif
 
 /**
+ * Creates an int value on a simulated device.
+ *
+ * Returns 0 if not in simulation; this can be used to avoid calls
+ * to Set/Get functions.
+ *
+ * @param device simulated device handle
+ * @param name value name
+ * @param direction input/output/bidir (from perspective of user code)
+ * @param initialValue initial value
+ * @return simulated value handle
+ */
+inline HAL_SimValueHandle HAL_CreateSimValueInt(HAL_SimDeviceHandle device,
+                                                const char* name,
+                                                int32_t direction,
+                                                int32_t initialValue) {
+  struct HAL_Value v = HAL_MakeInt(initialValue);
+  return HAL_CreateSimValue(device, name, direction, &v);
+}
+
+/**
+ * Creates a long value on a simulated device.
+ *
+ * Returns 0 if not in simulation; this can be used to avoid calls
+ * to Set/Get functions.
+ *
+ * @param device simulated device handle
+ * @param name value name
+ * @param direction input/output/bidir (from perspective of user code)
+ * @param initialValue initial value
+ * @return simulated value handle
+ */
+inline HAL_SimValueHandle HAL_CreateSimValueLong(HAL_SimDeviceHandle device,
+                                                 const char* name,
+                                                 int32_t direction,
+                                                 int64_t initialValue) {
+  struct HAL_Value v = HAL_MakeLong(initialValue);
+  return HAL_CreateSimValue(device, name, direction, &v);
+}
+
+/**
  * Creates a double value on a simulated device.
  *
  * Returns 0 if not in simulation; this can be used to avoid calls
@@ -94,16 +142,16 @@
  *
  * @param device simulated device handle
  * @param name value name
- * @param readonly if the value should not be written from simulation side
+ * @param direction input/output/bidir (from perspective of user code)
  * @param initialValue initial value
  * @return simulated value handle
  */
 inline HAL_SimValueHandle HAL_CreateSimValueDouble(HAL_SimDeviceHandle device,
                                                    const char* name,
-                                                   HAL_Bool readonly,
+                                                   int32_t direction,
                                                    double initialValue) {
   struct HAL_Value v = HAL_MakeDouble(initialValue);
-  return HAL_CreateSimValue(device, name, readonly, &v);
+  return HAL_CreateSimValue(device, name, direction, &v);
 }
 
 /**
@@ -116,19 +164,41 @@
  *
  * @param device simulated device handle
  * @param name value name
- * @param readonly if the value should not be written from simulation side
+ * @param direction input/output/bidir (from perspective of user code)
  * @param numOptions number of enumerated value options (length of options)
  * @param options array of option descriptions
  * @param initialValue initial value (selection)
  * @return simulated value handle
  */
 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);
 
 /**
+ * Creates an enumerated value on a simulated device with double values.
+ *
+ * Enumerated values are always in the range 0 to numOptions-1.
+ *
+ * Returns 0 if not in simulation; this can be used to avoid calls
+ * to Set/Get functions.
+ *
+ * @param device simulated device handle
+ * @param name value name
+ * @param direction input/output/bidir (from perspective of user code)
+ * @param numOptions number of enumerated value options (length of options)
+ * @param options array of option descriptions
+ * @param optionValues array of option double values
+ * @param initialValue initial value (selection)
+ * @return simulated value handle
+ */
+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);
+
+/**
  * Creates a boolean value on a simulated device.
  *
  * Returns 0 if not in simulation; this can be used to avoid calls
@@ -136,16 +206,16 @@
  *
  * @param device simulated device handle
  * @param name value name
- * @param readonly if the value should not be written from simulation side
+ * @param direction input/output/bidir (from perspective of user code)
  * @param initialValue initial value
  * @return simulated value handle
  */
 inline HAL_SimValueHandle HAL_CreateSimValueBoolean(HAL_SimDeviceHandle device,
                                                     const char* name,
-                                                    HAL_Bool readonly,
+                                                    int32_t direction,
                                                     HAL_Bool initialValue) {
   struct HAL_Value v = HAL_MakeBoolean(initialValue);
-  return HAL_CreateSimValue(device, name, readonly, &v);
+  return HAL_CreateSimValue(device, name, direction, &v);
 }
 
 /**
@@ -167,6 +237,30 @@
 #endif
 
 /**
+ * Gets a simulated value (int).
+ *
+ * @param handle simulated value handle
+ * @return The current value
+ */
+inline int32_t HAL_GetSimValueInt(HAL_SimValueHandle handle) {
+  struct HAL_Value v;
+  HAL_GetSimValue(handle, &v);
+  return v.type == HAL_INT ? v.data.v_int : 0;
+}
+
+/**
+ * Gets a simulated value (long).
+ *
+ * @param handle simulated value handle
+ * @return The current value
+ */
+inline int64_t HAL_GetSimValueLong(HAL_SimValueHandle handle) {
+  struct HAL_Value v;
+  HAL_GetSimValue(handle, &v);
+  return v.type == HAL_LONG ? v.data.v_long : 0;
+}
+
+/**
  * Gets a simulated value (double).
  *
  * @param handle simulated value handle
@@ -219,6 +313,28 @@
 #endif
 
 /**
+ * Sets a simulated value (int).
+ *
+ * @param handle simulated value handle
+ * @param value the value to set
+ */
+inline void HAL_SetSimValueInt(HAL_SimValueHandle handle, int value) {
+  struct HAL_Value v = HAL_MakeInt(value);
+  HAL_SetSimValue(handle, &v);
+}
+
+/**
+ * Sets a simulated value (long).
+ *
+ * @param handle simulated value handle
+ * @param value the value to set
+ */
+inline void HAL_SetSimValueLong(HAL_SimValueHandle handle, int64_t value) {
+  struct HAL_Value v = HAL_MakeLong(value);
+  HAL_SetSimValue(handle, &v);
+}
+
+/**
  * Sets a simulated value (double).
  *
  * @param handle simulated value handle
@@ -251,6 +367,17 @@
   HAL_SetSimValue(handle, &v);
 }
 
+/**
+ * Resets a simulated double or integral value to 0.
+ * Has no effect on other value types.
+ * Use this instead of Set(0) for resetting incremental sensor values like
+ * encoder counts or gyro accumulated angle to ensure correct behavior in a
+ * distributed system (e.g. WebSockets).
+ *
+ * @param handle simulated value handle
+ */
+void HAL_ResetSimValue(HAL_SimValueHandle handle);
+
 /** @} */
 
 #ifdef __cplusplus
@@ -276,7 +403,7 @@
    *
    * @param handle simulated value handle
    */
-  /*implicit*/ SimValue(HAL_SimValueHandle val)  // NOLINT(runtime/explicit)
+  /*implicit*/ SimValue(HAL_SimValueHandle val)  // NOLINT
       : m_handle(val) {}
 
   /**
@@ -292,7 +419,7 @@
    *
    * @return internal handle
    */
-  operator HAL_SimValueHandle() const { return m_handle; }
+  operator HAL_SimValueHandle() const { return m_handle; }  // NOLINT
 
   /**
    * Gets the simulated value.
@@ -313,6 +440,88 @@
 };
 
 /**
+ * C++ wrapper around a HAL simulator int value handle.
+ */
+class SimInt : public SimValue {
+ public:
+  /**
+   * Default constructor that results in an "empty" object that is false in
+   * a boolean context.
+   */
+  SimInt() = default;
+
+  /**
+   * Wraps a simulated value handle as returned by HAL_CreateSimValueInt().
+   *
+   * @param handle simulated value handle
+   */
+  /*implicit*/ SimInt(HAL_SimValueHandle val)  // NOLINT
+      : SimValue(val) {}
+
+  /**
+   * Gets the simulated value.
+   *
+   * @return The current value
+   */
+  int32_t Get() const { return HAL_GetSimValueInt(m_handle); }
+
+  /**
+   * Sets the simulated value.
+   *
+   * @param value the value to set
+   */
+  void Set(int32_t value) { HAL_SetSimValueInt(m_handle, value); }
+
+  /**
+   * Resets the simulated value to 0. Use this instead of Set(0) for resetting
+   * incremental sensor values like encoder counts or gyro accumulated angle
+   * to ensure correct behavior in a distributed system (e.g. WebSockets).
+   */
+  void Reset() { HAL_ResetSimValue(m_handle); }
+};
+
+/**
+ * C++ wrapper around a HAL simulator long value handle.
+ */
+class SimLong : public SimValue {
+ public:
+  /**
+   * Default constructor that results in an "empty" object that is false in
+   * a boolean context.
+   */
+  SimLong() = default;
+
+  /**
+   * Wraps a simulated value handle as returned by HAL_CreateSimValueLong().
+   *
+   * @param handle simulated value handle
+   */
+  /*implicit*/ SimLong(HAL_SimValueHandle val)  // NOLINT
+      : SimValue(val) {}
+
+  /**
+   * Gets the simulated value.
+   *
+   * @return The current value
+   */
+  int64_t Get() const { return HAL_GetSimValueLong(m_handle); }
+
+  /**
+   * Sets the simulated value.
+   *
+   * @param value the value to set
+   */
+  void Set(int64_t value) { HAL_SetSimValueLong(m_handle, value); }
+
+  /**
+   * Resets the simulated value to 0. Use this instead of Set(0) for resetting
+   * incremental sensor values like encoder counts or gyro accumulated angle
+   * to ensure correct behavior in a distributed system (e.g. WebSockets).
+   */
+  void Reset() { HAL_ResetSimValue(m_handle); }
+};
+
+/**
  * C++ wrapper around a HAL simulator double value handle.
  */
 class SimDouble : public SimValue {
@@ -328,7 +537,7 @@
    *
    * @param handle simulated value handle
    */
-  /*implicit*/ SimDouble(HAL_SimValueHandle val)  // NOLINT(runtime/explicit)
+  /*implicit*/ SimDouble(HAL_SimValueHandle val)  // NOLINT
       : SimValue(val) {}
 
   /**
@@ -344,6 +553,13 @@
    * @param value the value to set
    */
   void Set(double value) { HAL_SetSimValueDouble(m_handle, value); }
+
+  /**
+   * Resets the simulated value to 0. Use this instead of Set(0) for resetting
+   * incremental sensor values like encoder counts or gyro accumulated angle
+   * to ensure correct behavior in a distributed system (e.g. WebSockets).
+   */
+  void Reset() { HAL_ResetSimValue(m_handle); }
 };
 
 /**
@@ -362,7 +578,7 @@
    *
    * @param handle simulated value handle
    */
-  /*implicit*/ SimEnum(HAL_SimValueHandle val)  // NOLINT(runtime/explicit)
+  /*implicit*/ SimEnum(HAL_SimValueHandle val)  // NOLINT
       : SimValue(val) {}
 
   /**
@@ -396,7 +612,7 @@
    *
    * @param handle simulated value handle
    */
-  /*implicit*/ SimBoolean(HAL_SimValueHandle val)  // NOLINT(runtime/explicit)
+  /*implicit*/ SimBoolean(HAL_SimValueHandle val)  // NOLINT
       : SimValue(val) {}
 
   /**
@@ -420,6 +636,15 @@
 class SimDevice {
  public:
   /**
+   * Direction of a simulated value (from the perspective of user code).
+   */
+  enum Direction {
+    kInput = HAL_SimValueInput,
+    kOutput = HAL_SimValueOutput,
+    kBidir = HAL_SimValueBidir
+  };
+
+  /**
    * Default constructor that results in an "empty" object that is false in
    * a boolean context.
    */
@@ -474,7 +699,9 @@
   SimDevice(const char* name, int index, int channel);
 
   ~SimDevice() {
-    if (m_handle != HAL_kInvalidHandle) HAL_FreeSimDevice(m_handle);
+    if (m_handle != HAL_kInvalidHandle) {
+      HAL_FreeSimDevice(m_handle);
+    }
   }
 
   SimDevice(const SimDevice&) = delete;
@@ -503,7 +730,7 @@
    *
    * @return internal handle
    */
-  operator HAL_SimDeviceHandle() const { return m_handle; }
+  operator HAL_SimDeviceHandle() const { return m_handle; }  // NOLINT
 
   /**
    * Creates a value on the simulated device.
@@ -512,13 +739,44 @@
    * in a boolean context.
    *
    * @param name value name
-   * @param readonly if the value should not be written from simulation side
+   * @param direction input/output/bidir (from perspective of user code)
    * @param initialValue initial value
    * @return simulated value object
    */
-  SimValue CreateValue(const char* name, bool readonly,
+  SimValue CreateValue(const char* name, int32_t direction,
                        const HAL_Value& initialValue) {
-    return HAL_CreateSimValue(m_handle, name, readonly, &initialValue);
+    return HAL_CreateSimValue(m_handle, name, direction, &initialValue);
+  }
+
+  /**
+   * Creates an int value on the simulated device.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated double value object
+   */
+  SimInt CreateInt(const char* name, int32_t direction, int32_t initialValue) {
+    return HAL_CreateSimValueInt(m_handle, name, direction, initialValue);
+  }
+
+  /**
+   * Creates a long value on the simulated device.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param initialValue initial value
+   * @return simulated double value object
+   */
+  SimLong CreateLong(const char* name, int32_t direction,
+                     int64_t initialValue) {
+    return HAL_CreateSimValueLong(m_handle, name, direction, initialValue);
   }
 
   /**
@@ -528,12 +786,13 @@
    * in a boolean context.
    *
    * @param name value name
-   * @param readonly if the value should not be written from simulation side
+   * @param direction input/output/bidir (from perspective of user code)
    * @param initialValue initial value
    * @return simulated double value object
    */
-  SimDouble CreateDouble(const char* name, bool readonly, double initialValue) {
-    return HAL_CreateSimValueDouble(m_handle, name, readonly, initialValue);
+  SimDouble CreateDouble(const char* name, int32_t direction,
+                         double initialValue) {
+    return HAL_CreateSimValueDouble(m_handle, name, direction, initialValue);
   }
 
   /**
@@ -545,15 +804,15 @@
    * in a boolean context.
    *
    * @param name value name
-   * @param readonly if the value should not be written from simulation side
+   * @param direction input/output/bidir (from perspective of user code)
    * @param options array of option descriptions
    * @param initialValue initial value (selection)
    * @return simulated enum value object
    */
-  SimEnum CreateEnum(const char* name, bool readonly,
+  SimEnum CreateEnum(const char* name, int32_t direction,
                      std::initializer_list<const char*> options,
                      int32_t initialValue) {
-    return HAL_CreateSimValueEnum(m_handle, name, readonly, options.size(),
+    return HAL_CreateSimValueEnum(m_handle, name, direction, options.size(),
                                   const_cast<const char**>(options.begin()),
                                   initialValue);
   }
@@ -567,31 +826,91 @@
    * in a boolean context.
    *
    * @param name value name
-   * @param readonly if the value should not be written from simulation side
+   * @param direction input/output/bidir (from perspective of user code)
    * @param options array of option descriptions
    * @param initialValue initial value (selection)
    * @return simulated enum value object
    */
-  SimEnum CreateEnum(const char* name, bool readonly,
-                     wpi::ArrayRef<const char*> options, int32_t initialValue) {
-    return HAL_CreateSimValueEnum(m_handle, name, readonly, options.size(),
+  SimEnum CreateEnum(const char* name, int32_t direction,
+                     wpi::span<const char* const> options,
+                     int32_t initialValue) {
+    return HAL_CreateSimValueEnum(m_handle, name, direction, options.size(),
                                   const_cast<const char**>(options.data()),
                                   initialValue);
   }
 
   /**
+   * Creates an enumerated value on the simulated device with double values.
+   *
+   * Enumerated values are always in the range 0 to numOptions-1.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param options array of option descriptions
+   * @param optionValues array of option values (must be the same size as
+   *                     options)
+   * @param initialValue initial value (selection)
+   * @return simulated enum value object
+   */
+  SimEnum CreateEnumDouble(const char* name, int32_t direction,
+                           std::initializer_list<const char*> options,
+                           std::initializer_list<double> optionValues,
+                           int32_t initialValue) {
+    if (options.size() != optionValues.size()) {
+      return {};
+    }
+    return HAL_CreateSimValueEnumDouble(
+        m_handle, name, direction, options.size(),
+        const_cast<const char**>(options.begin()), optionValues.begin(),
+        initialValue);
+  }
+
+  /**
+   * Creates an enumerated value on the simulated device with double values.
+   *
+   * Enumerated values are always in the range 0 to numOptions-1.
+   *
+   * If not in simulation, results in an "empty" object that evaluates to false
+   * in a boolean context.
+   *
+   * @param name value name
+   * @param direction input/output/bidir (from perspective of user code)
+   * @param options array of option descriptions
+   * @param optionValues array of option values (must be the same size as
+   *                     options)
+   * @param initialValue initial value (selection)
+   * @return simulated enum value object
+   */
+  SimEnum CreateEnumDouble(const char* name, int32_t direction,
+                           wpi::span<const char* const> options,
+                           wpi::span<const double> optionValues,
+                           int32_t initialValue) {
+    if (options.size() != optionValues.size()) {
+      return {};
+    }
+    return HAL_CreateSimValueEnumDouble(
+        m_handle, name, direction, options.size(),
+        const_cast<const char**>(options.data()), optionValues.data(),
+        initialValue);
+  }
+
+  /**
    * Creates a boolean value on the simulated device.
    *
    * If not in simulation, results in an "empty" object that evaluates to false
    * in a boolean context.
    *
    * @param name value name
-   * @param readonly if the value should not be written from simulation side
+   * @param direction input/output/bidir (from perspective of user code)
    * @param initialValue initial value
    * @return simulated boolean value object
    */
-  SimBoolean CreateBoolean(const char* name, bool readonly, bool initialValue) {
-    return HAL_CreateSimValueBoolean(m_handle, name, readonly, initialValue);
+  SimBoolean CreateBoolean(const char* name, int32_t direction,
+                           bool initialValue) {
+    return HAL_CreateSimValueBoolean(m_handle, name, direction, initialValue);
   }
 
  protected:
diff --git a/hal/src/main/native/include/hal/Solenoid.h b/hal/src/main/native/include/hal/Solenoid.h
deleted file mode 100644
index 53257b2..0000000
--- a/hal/src/main/native/include/hal/Solenoid.h
+++ /dev/null
@@ -1,141 +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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#pragma once
-
-#include <stdint.h>
-
-#include "hal/Types.h"
-
-/**
- * @defgroup hal_solenoid Solenoid Output Functions
- * @ingroup hal_capi
- * @{
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Initializes a solenoid port.
- *
- * @param portHandle the port handle of the module and channel to initialize
- * @return           the created solenoid handle
- */
-HAL_SolenoidHandle HAL_InitializeSolenoidPort(HAL_PortHandle portHandle,
-                                              int32_t* status);
-
-/**
- * Frees a solenoid port.
- *
- * @param solenoidPortHandle the solenoid handle
- */
-void HAL_FreeSolenoidPort(HAL_SolenoidHandle solenoidPortHandle);
-
-/**
- * Checks if a solenoid module is in the valid range.
- *
- * @param module the module number to check
- * @return       true if the module number is valid, otherwise false
- */
-HAL_Bool HAL_CheckSolenoidModule(int32_t module);
-
-/**
- * Checks if a solenoid channel is in the valid range.
- *
- * @param channel the channel number to check
- * @return       true if the channel number is valid, otherwise false
- */
-HAL_Bool HAL_CheckSolenoidChannel(int32_t channel);
-
-/**
- * Gets the current solenoid output value.
- *
- * @param solenoidPortHandle the solenoid handle
- * @return                   true if the solenoid is on, otherwise false
- */
-HAL_Bool HAL_GetSolenoid(HAL_SolenoidHandle solenoidPortHandle,
-                         int32_t* status);
-
-/**
- * Gets the status of all solenoids on a specific module.
- *
- * @param module the module to check
- * @return       bitmask of the channels, 1 for on 0 for off
- */
-int32_t HAL_GetAllSolenoids(int32_t module, int32_t* status);
-
-/**
- * Sets a solenoid output value.
- *
- * @param solenoidPortHandle the solenoid handle
- * @param value              true for on, false for off
- */
-void HAL_SetSolenoid(HAL_SolenoidHandle solenoidPortHandle, HAL_Bool value,
-                     int32_t* status);
-
-/**
- * Sets all channels on a specific module.
- *
- * @param module the module to set the channels on
- * @param state  bitmask of the channels to set, 1 for on 0 for off
- */
-void HAL_SetAllSolenoids(int32_t module, int32_t state, int32_t* status);
-
-/**
- * Gets the channels blacklisted from being enabled on a module.
- *
- * @param module the module to check
- * @retur        bitmask of the blacklisted channels, 1 for true 0 for false
- */
-int32_t HAL_GetPCMSolenoidBlackList(int32_t module, int32_t* status);
-
-/**
- * Gets if a specific module has an over or under voltage sticky fault.
- *
- * @param module the module to check
- * @return       true if a stick fault is set, otherwise false
- */
-HAL_Bool HAL_GetPCMSolenoidVoltageStickyFault(int32_t module, int32_t* status);
-
-/**
- * Gets if a specific module has an over or under voltage fault.
- *
- * @param module the module to check
- * @return       true if faulted, otherwise false
- */
-HAL_Bool HAL_GetPCMSolenoidVoltageFault(int32_t module, int32_t* status);
-
-/**
- * Clears all faults on a module.
- *
- * @param module the module to clear
- */
-void HAL_ClearAllPCMStickyFaults(int32_t module, int32_t* status);
-
-/**
- * Sets the one shot duration on a solenoid channel.
- *
- * @param solenoidPortHandle the solenoid handle
- * @param durMS              the one shot duration in ms
- */
-void HAL_SetOneShotDuration(HAL_SolenoidHandle solenoidPortHandle,
-                            int32_t durMS, int32_t* status);
-
-/**
- * Fires a single pulse on a solenoid channel.
- *
- * The pulse is the duration set by HAL_SetOneShotDuration().
- *
- * @param solenoidPortHandle the solenoid handle
- */
-void HAL_FireOneShot(HAL_SolenoidHandle solenoidPortHandle, int32_t* status);
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-/** @} */
diff --git a/hal/src/main/native/include/hal/Threads.h b/hal/src/main/native/include/hal/Threads.h
index aea4399..a6db5e0 100644
--- a/hal/src/main/native/include/hal/Threads.h
+++ b/hal/src/main/native/include/hal/Threads.h
@@ -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.
 
 #pragma once
 
@@ -24,11 +21,13 @@
 /**
  * Gets the thread priority for the specified thread.
  *
- * @param handle     Native handle pointer to the thread to get the priority for
- * @param isRealTime Set to true if thread is realtime, otherwise false
- * @param status     Error status variable. 0 on success
- * @return           The current thread priority. Scaled 1-99, with 1 being
- * highest.
+ * @param[in] handle      Native handle pointer to the thread to get the
+ *                        priority for.
+ * @param[out] isRealTime Set to true if thread is real-time, otherwise false.
+ * @param[out] status     Error status variable. 0 on success.
+ * @return The current thread priority. For real-time, this is 1-99 with 99
+ *         being highest. For non-real-time, this is 0. See "man 7 sched" for
+ *         details.
  */
 int32_t HAL_GetThreadPriority(NativeThreadHandle handle, HAL_Bool* isRealTime,
                               int32_t* status);
@@ -36,24 +35,25 @@
 /**
  * Gets the thread priority for the current thread.
  *
- * @param handle     Native handle pointer to the thread to get the priority for
- * @param isRealTime Set to true if thread is realtime, otherwise false
- * @param status     Error status variable. 0 on success
- * @return           The current thread priority. Scaled 1-99, with 1 being
- * highest.
+ * @param[out] isRealTime Set to true if thread is real-time, otherwise false.
+ * @param[out] status     Error status variable. 0 on success.
+ * @return The current thread priority. For real-time, this is 1-99 with 99
+ *         being highest. For non-real-time, this is 0. See "man 7 sched" for
+ *         details.
  */
 int32_t HAL_GetCurrentThreadPriority(HAL_Bool* isRealTime, int32_t* status);
 
 /**
  * Sets the thread priority for the specified thread.
  *
- * @param thread   Reference to the thread to set the priority of
- * @param realTime Set to true to set a realtime priority, false for standard
- * priority
- * @param priority Priority to set the thread to. Scaled 1-99, with 1 being
- * highest
- * @param status   Error status variable. 0 on success
- * @return         The success state of setting the priority
+ * @param[in] handle   Reference to the thread to set the priority of.
+ * @param[in] realTime Set to true to set a real-time priority, false for
+ *                     standard priority.
+ * @param[in] priority Priority to set the thread to. For real-time, this is
+ *                     1-99 with 99 being highest. For non-real-time, this is
+ *                     forced to 0. See "man 7 sched" for more details.
+ * @param[out] status  Error status variable. 0 on success.
+ * @return True on success.
  */
 HAL_Bool HAL_SetThreadPriority(NativeThreadHandle handle, HAL_Bool realTime,
                                int32_t priority, int32_t* status);
@@ -61,13 +61,13 @@
 /**
  * Sets the thread priority for the current thread.
  *
- * @param thread   Reference to the thread to set the priority of
- * @param realTime Set to true to set a realtime priority, false for standard
- * priority
- * @param priority Priority to set the thread to. Scaled 1-99, with 1 being
- * highest
- * @param status   Error status variable. 0 on success
- * @return         The success state of setting the priority
+ * @param[in] realTime Set to true to set a real-time priority, false for
+ *                     standard priority.
+ * @param[in] priority Priority to set the thread to. For real-time, this is
+ *                     1-99 with 99 being highest. For non-real-time, this is
+ *                     forced to 0. See "man 7 sched" for more details.
+ * @param[out] status  Error status variable. 0 on success.
+ * @return True on success.
  */
 HAL_Bool HAL_SetCurrentThreadPriority(HAL_Bool realTime, int32_t priority,
                                       int32_t* status);
diff --git a/hal/src/main/native/include/hal/Types.h b/hal/src/main/native/include/hal/Types.h
index 1ebbe2d..6b95447 100644
--- a/hal/src/main/native/include/hal/Types.h
+++ b/hal/src/main/native/include/hal/Types.h
@@ -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.
 
 #pragma once
 
@@ -65,6 +62,14 @@
 
 typedef HAL_CANHandle HAL_PDPHandle;
 
+typedef HAL_Handle HAL_PowerDistributionHandle;
+
+typedef HAL_Handle HAL_CTREPCMHandle;
+
+typedef HAL_Handle HAL_REVPDHHandle;
+
+typedef HAL_Handle HAL_REVPHHandle;
+
 typedef int32_t HAL_Bool;
 
 #ifdef __cplusplus
@@ -86,7 +91,7 @@
 class Handle {
  public:
   Handle() = default;
-  /*implicit*/ Handle(CType val) : m_handle(val) {}  // NOLINT(runtime/explicit)
+  /*implicit*/ Handle(CType val) : m_handle(val) {}  // NOLINT
 
   Handle(const Handle&) = delete;
   Handle& operator=(const Handle&) = delete;
@@ -99,7 +104,7 @@
     return *this;
   }
 
-  operator CType() const { return m_handle; }
+  operator CType() const { return m_handle; }  // NOLINT
 
  private:
   CType m_handle = CInvalid;
diff --git a/hal/src/main/native/include/hal/Value.h b/hal/src/main/native/include/hal/Value.h
index 578d989..ff72ee7 100644
--- a/hal/src/main/native/include/hal/Value.h
+++ b/hal/src/main/native/include/hal/Value.h
@@ -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.
 
 #pragma once
 
diff --git a/hal/src/main/native/include/hal/cpp/SerialHelper.h b/hal/src/main/native/include/hal/cpp/SerialHelper.h
index 9f4d6a0..13b6857 100644
--- a/hal/src/main/native/include/hal/cpp/SerialHelper.h
+++ b/hal/src/main/native/include/hal/cpp/SerialHelper.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
 
@@ -29,34 +26,34 @@
   /**
    * Get the VISA name of a serial port.
    *
-   * @param port   the serial port index
-   * @param status status check
-   * @return       the VISA name
+   * @param[in] port    the serial port index
+   * @param[out] status status check
+   * @return the VISA name
    */
   std::string GetVISASerialPortName(HAL_SerialPort port, int32_t* status);
 
   /**
    * Get the OS name of a serial port.
    *
-   * @param port   the serial port index
-   * @param status status check
-   * @return       the OS name
+   * @param[in] port    the serial port index
+   * @param[out] status status check
+   * @return the OS name
    */
   std::string GetOSSerialPortName(HAL_SerialPort port, int32_t* status);
 
   /**
    * Get a vector of all serial port VISA names.
    *
-   * @param status status check
-   * @return       vector of serial port VISA names
+   * @param[out] status status check
+   * @return vector of serial port VISA names
    */
   std::vector<std::string> GetVISASerialPortList(int32_t* status);
 
   /**
    * Get a vector of all serial port OS names.
    *
-   * @param status status check
-   * @return       vector of serial port OS names
+   * @param[out] status status check
+   * @return vector of serial port OS names
    */
   std::vector<std::string> GetOSSerialPortList(int32_t* status);
 
diff --git a/hal/src/main/native/include/hal/cpp/UnsafeDIO.h b/hal/src/main/native/include/hal/cpp/UnsafeDIO.h
index dad5eb7..eb7f231 100644
--- a/hal/src/main/native/include/hal/cpp/UnsafeDIO.h
+++ b/hal/src/main/native/include/hal/cpp/UnsafeDIO.h
@@ -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.
 
 #pragma once
 
@@ -61,9 +58,9 @@
  * functions on the Proxy object passed as a parameter can deadlock your
  * program.
  *
- * @param handle the HAL digital handle of the pin to toggle.
- * @param status status check
- * @param func   A functor taking a ref to a DIOSetProxy object.
+ * @param[in] handle the HAL digital handle of the pin to toggle.
+ * @param[out] status status check
+ * @param[in] func   A functor taking a ref to a DIOSetProxy object.
  */
 template <typename Functor>
 void UnsafeManipulateDIO(HAL_DigitalHandle handle, int32_t* status,
@@ -76,7 +73,9 @@
   wpi::mutex& dioMutex = detail::UnsafeGetDIOMutex();
   tDIO* dSys = detail::UnsafeGetDigialSystem();
   auto mask = detail::ComputeDigitalMask(handle, status);
-  if (status != 0) return;
+  if (*status != 0) {
+    return;
+  }
   std::scoped_lock lock(dioMutex);
 
   tDIO::tOutputEnable enableOE = dSys->readOutputEnable(status);
diff --git a/hal/src/main/native/include/hal/cpp/fpga_clock.h b/hal/src/main/native/include/hal/cpp/fpga_clock.h
index f6d5c6c..0f7bb75 100644
--- a/hal/src/main/native/include/hal/cpp/fpga_clock.h
+++ b/hal/src/main/native/include/hal/cpp/fpga_clock.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/include/hal/handles/DigitalHandleResource.h b/hal/src/main/native/include/hal/handles/DigitalHandleResource.h
index 5fd8506..5154a43 100644
--- a/hal/src/main/native/include/hal/handles/DigitalHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/DigitalHandleResource.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
 
@@ -25,7 +22,7 @@
  * allows a limited number of handles that are allocated by index.
  * The enum value is separate, as 2 enum values are allowed per handle
  * Because they are allocated by index, each individual index holds its own
- * mutex, which reduces contention heavily.]
+ * mutex, which reduces contention heavily.
  *
  * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
  * @tparam TStruct The struct type held by this resource
@@ -41,7 +38,8 @@
   DigitalHandleResource(const DigitalHandleResource&) = delete;
   DigitalHandleResource& operator=(const DigitalHandleResource&) = delete;
 
-  THandle Allocate(int16_t index, HAL_HandleEnum enumValue, int32_t* status);
+  std::shared_ptr<TStruct> Allocate(int16_t index, HAL_HandleEnum enumValue,
+                                    THandle* handle, int32_t* status);
   int16_t GetIndex(THandle handle, HAL_HandleEnum enumValue) {
     return getHandleTypedIndex(handle, enumValue, m_version);
   }
@@ -55,21 +53,27 @@
 };
 
 template <typename THandle, typename TStruct, int16_t size>
-THandle DigitalHandleResource<THandle, TStruct, size>::Allocate(
-    int16_t index, HAL_HandleEnum enumValue, int32_t* status) {
+std::shared_ptr<TStruct>
+DigitalHandleResource<THandle, TStruct, size>::Allocate(
+    int16_t index, HAL_HandleEnum enumValue, THandle* handle, int32_t* status) {
   // don't acquire the lock if we can fail early.
   if (index < 0 || index >= size) {
+    *handle = HAL_kInvalidHandle;
     *status = RESOURCE_OUT_OF_RANGE;
-    return HAL_kInvalidHandle;
+    return nullptr;
   }
   std::scoped_lock lock(m_handleMutexes[index]);
   // check for allocation, otherwise allocate and return a valid handle
   if (m_structures[index] != nullptr) {
+    *handle = HAL_kInvalidHandle;
     *status = RESOURCE_IS_ALLOCATED;
-    return HAL_kInvalidHandle;
+    return m_structures[index];
   }
   m_structures[index] = std::make_shared<TStruct>();
-  return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
+  *handle =
+      static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
+  *status = HAL_SUCCESS;
+  return m_structures[index];
 }
 
 template <typename THandle, typename TStruct, int16_t size>
@@ -91,7 +95,9 @@
     THandle handle, HAL_HandleEnum enumValue) {
   // get handle index, and fail early if index out of range or wrong handle
   int16_t index = GetIndex(handle, enumValue);
-  if (index < 0 || index >= size) return;
+  if (index < 0 || index >= size) {
+    return;
+  }
   // lock and deallocated handle
   std::scoped_lock lock(m_handleMutexes[index]);
   m_structures[index].reset();
diff --git a/hal/src/main/native/include/hal/handles/HandlesInternal.h b/hal/src/main/native/include/hal/handles/HandlesInternal.h
index 511433e..13a56db 100644
--- a/hal/src/main/native/include/hal/handles/HandlesInternal.h
+++ b/hal/src/main/native/include/hal/handles/HandlesInternal.h
@@ -1,14 +1,13 @@
-/*----------------------------------------------------------------------------*/
-/* 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.
 
 #pragma once
 
 #include <stdint.h>
 
+#include <wpi/Synchronization.h>
+
 #include "hal/Types.h"
 
 /* General Handle Data Layout
@@ -46,7 +45,7 @@
  */
 enum class HAL_HandleEnum {
   Undefined = 0,
-  DIO = 1,
+  DIO = wpi::kHandleTypeHALBase,
   Port = 2,
   Notifier = 3,
   Interrupt = 4,
@@ -69,13 +68,17 @@
   DutyCycle = 21,
   DMA = 22,
   AddressableLED = 23,
+  CTREPCM = 24,
+  CTREPDP = 25,
+  REVPDH = 26,
+  REVPH = 27,
 };
 
 /**
  * Get the handle index from a handle.
  *
  * @param handle the handle
- * @return       the index
+ * @return the index
  */
 static inline int16_t getHandleIndex(HAL_Handle handle) {
   // mask and return last 16 bits
@@ -86,7 +89,7 @@
  * Get the handle type from a handle.
  *
  * @param handle the handle
- * @return       the type
+ * @return the type
  */
 static inline HAL_HandleEnum getHandleType(HAL_Handle handle) {
   // mask first 8 bits and cast to enum
@@ -98,7 +101,7 @@
  *
  * @param handle     the handle
  * @param handleType the type to check
- * @return           true if the type is correct, otherwise false
+ * @return true if the type is correct, otherwise false
  */
 static inline bool isHandleType(HAL_Handle handle, HAL_HandleEnum handleType) {
   return handleType == getHandleType(handle);
@@ -111,7 +114,7 @@
  *
  * @param handle  the handle
  * @param version the handle version to check
- * @return        true if the handle is the right version, otherwise false
+ * @return true if the handle is the right version, otherwise false
  */
 static inline bool isHandleCorrectVersion(HAL_Handle handle, int16_t version) {
   return (((handle & 0xFF0000) >> 16) & version) == version;
@@ -123,17 +126,20 @@
  * Note the version is not checked on the roboRIO.
  *
  * @param handle     the handle
- * @param handleType the type to check
+ * @param enumType   the type to check
  * @param version    the handle version to check
- * @return           true if the handle is proper version and type, otherwise
- * false.
+ * @return true if the handle is proper version and type, otherwise
+ *         false.
  */
-static inline int16_t getHandleTypedIndex(HAL_Handle handle,
-                                          HAL_HandleEnum enumType,
-                                          int16_t version) {
-  if (!isHandleType(handle, enumType)) return InvalidHandleIndex;
+inline int16_t getHandleTypedIndex(HAL_Handle handle, HAL_HandleEnum enumType,
+                                   int16_t version) {
+  if (!isHandleType(handle, enumType)) {
+    return InvalidHandleIndex;
+  }
 #if !defined(__FRC_ROBORIO__)
-  if (!isHandleCorrectVersion(handle, version)) return InvalidHandleIndex;
+  if (!isHandleCorrectVersion(handle, version)) {
+    return InvalidHandleIndex;
+  }
 #endif
   return getHandleIndex(handle);
 }
@@ -152,10 +158,12 @@
  * Gets the port channel of a port handle.
  *
  * @param handle the port handle
- * @return       the port channel
+ * @return the port channel
  */
-static inline int16_t getPortHandleChannel(HAL_PortHandle handle) {
-  if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+inline int16_t getPortHandleChannel(HAL_PortHandle handle) {
+  if (!isHandleType(handle, HAL_HandleEnum::Port)) {
+    return InvalidHandleIndex;
+  }
   return static_cast<uint8_t>(handle & 0xff);
 }
 
@@ -164,10 +172,12 @@
  * Gets the port module of a port handle.
  *
  * @param handle the port handle
- * @return       the port module
+ * @return the port module
  */
-static inline int16_t getPortHandleModule(HAL_PortHandle handle) {
-  if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+inline int16_t getPortHandleModule(HAL_PortHandle handle) {
+  if (!isHandleType(handle, HAL_HandleEnum::Port)) {
+    return InvalidHandleIndex;
+  }
   return static_cast<uint8_t>((handle >> 8) & 0xff);
 }
 
@@ -176,10 +186,12 @@
  * Gets the SPI channel of a port handle.
  *
  * @param handle the port handle
- * @return       the port SPI channel
+ * @return the port SPI channel
  */
-static inline int16_t getPortHandleSPIEnable(HAL_PortHandle handle) {
-  if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
+inline int16_t getPortHandleSPIEnable(HAL_PortHandle handle) {
+  if (!isHandleType(handle, HAL_HandleEnum::Port)) {
+    return InvalidHandleIndex;
+  }
   return static_cast<uint8_t>((handle >> 16) & 0xff);
 }
 
@@ -188,7 +200,7 @@
  *
  * @param channel the channel
  * @param module  the module
- * @return        port handle for the module and channel
+ * @return port handle for the module and channel
  */
 HAL_PortHandle createPortHandle(uint8_t channel, uint8_t module);
 
@@ -196,7 +208,7 @@
  * Create a port handle for SPI.
  *
  * @param channel the SPI channel
- * @return        port handle for the channel
+ * @return port handle for the channel
  */
 HAL_PortHandle createPortHandleForSPI(uint8_t channel);
 
@@ -208,7 +220,7 @@
  * @param index      the index
  * @param handleType the handle type
  * @param version    the handle version
- * @return           the created handle
+ * @return the created handle
  */
 HAL_Handle createHandle(int16_t index, HAL_HandleEnum handleType,
                         int16_t version);
diff --git a/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h b/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h
index 902f023..d96de2b 100644
--- a/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/IndexedClassedHandleResource.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
 
@@ -52,7 +49,7 @@
   }
   std::shared_ptr<TStruct> Get(THandle handle);
   void Free(THandle handle);
-  void ResetHandles();
+  void ResetHandles() override;
 
  private:
   std::array<std::shared_ptr<TStruct>, size> m_structures;
@@ -101,7 +98,9 @@
     THandle handle) {
   // get handle index, and fail early if index out of range or wrong handle
   int16_t index = GetIndex(handle);
-  if (index < 0 || index >= size) return;
+  if (index < 0 || index >= size) {
+    return;
+  }
   // lock and deallocated handle
   std::scoped_lock lock(m_handleMutexes[index]);
   m_structures[index].reset();
diff --git a/hal/src/main/native/include/hal/handles/IndexedHandleResource.h b/hal/src/main/native/include/hal/handles/IndexedHandleResource.h
index 26fda02..2e921ee 100644
--- a/hal/src/main/native/include/hal/handles/IndexedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/IndexedHandleResource.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
 
@@ -42,7 +39,8 @@
   IndexedHandleResource(const IndexedHandleResource&) = delete;
   IndexedHandleResource& operator=(const IndexedHandleResource&) = delete;
 
-  THandle Allocate(int16_t index, int32_t* status);
+  std::shared_ptr<TStruct> Allocate(int16_t index, THandle* handle,
+                                    int32_t* status);
   int16_t GetIndex(THandle handle) {
     return getHandleTypedIndex(handle, enumValue, m_version);
   }
@@ -57,21 +55,27 @@
 
 template <typename THandle, typename TStruct, int16_t size,
           HAL_HandleEnum enumValue>
-THandle IndexedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
-    int16_t index, int32_t* status) {
+std::shared_ptr<TStruct>
+IndexedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
+    int16_t index, THandle* handle, int32_t* status) {
   // don't acquire the lock if we can fail early.
   if (index < 0 || index >= size) {
     *status = RESOURCE_OUT_OF_RANGE;
-    return HAL_kInvalidHandle;
+    *handle = HAL_kInvalidHandle;
+    return nullptr;
   }
   std::scoped_lock lock(m_handleMutexes[index]);
   // check for allocation, otherwise allocate and return a valid handle
   if (m_structures[index] != nullptr) {
     *status = RESOURCE_IS_ALLOCATED;
-    return HAL_kInvalidHandle;
+    *handle = HAL_kInvalidHandle;
+    return m_structures[index];
   }
   m_structures[index] = std::make_shared<TStruct>();
-  return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
+  *handle =
+      static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
+  *status = HAL_SUCCESS;
+  return m_structures[index];
 }
 
 template <typename THandle, typename TStruct, int16_t size,
@@ -95,7 +99,9 @@
     THandle handle) {
   // get handle index, and fail early if index out of range or wrong handle
   int16_t index = GetIndex(handle);
-  if (index < 0 || index >= size) return;
+  if (index < 0 || index >= size) {
+    return;
+  }
   // lock and deallocated handle
   std::scoped_lock lock(m_handleMutexes[index]);
   m_structures[index].reset();
diff --git a/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h b/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h
index 0ab8aac..2650708 100644
--- a/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/LimitedClassedHandleResource.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
 
@@ -96,7 +93,9 @@
     THandle handle) {
   // get handle index, and fail early if index out of range or wrong handle
   int16_t index = GetIndex(handle);
-  if (index < 0 || index >= size) return;
+  if (index < 0 || index >= size) {
+    return;
+  }
   // lock and deallocated handle
   std::scoped_lock allocateLock(m_allocateMutex);
   std::scoped_lock handleLock(m_handleMutexes[index]);
diff --git a/hal/src/main/native/include/hal/handles/LimitedHandleResource.h b/hal/src/main/native/include/hal/handles/LimitedHandleResource.h
index 2f7ed0d..6f76293 100644
--- a/hal/src/main/native/include/hal/handles/LimitedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/LimitedHandleResource.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
 
@@ -91,7 +88,9 @@
     THandle handle) {
   // get handle index, and fail early if index out of range or wrong handle
   int16_t index = GetIndex(handle);
-  if (index < 0 || index >= size) return;
+  if (index < 0 || index >= size) {
+    return;
+  }
   // lock and deallocated handle
   std::scoped_lock allocateLock(m_allocateMutex);
   std::scoped_lock handleLock(m_handleMutexes[index]);
diff --git a/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h b/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h
index 5f74b88..09510ac 100644
--- a/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h
+++ b/hal/src/main/native/include/hal/handles/UnlimitedHandleResource.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2008-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -74,7 +71,9 @@
       return static_cast<THandle>(createHandle(i, enumValue, m_version));
     }
   }
-  if (i >= INT16_MAX) return HAL_kInvalidHandle;
+  if (i >= INT16_MAX) {
+    return HAL_kInvalidHandle;
+  }
 
   m_structures.push_back(structure);
   return static_cast<THandle>(
@@ -86,8 +85,9 @@
 UnlimitedHandleResource<THandle, TStruct, enumValue>::Get(THandle handle) {
   int16_t index = GetIndex(handle);
   std::scoped_lock lock(m_handleMutex);
-  if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
+  if (index < 0 || index >= static_cast<int16_t>(m_structures.size())) {
     return nullptr;
+  }
   return m_structures[index];
 }
 
@@ -96,8 +96,9 @@
 UnlimitedHandleResource<THandle, TStruct, enumValue>::Free(THandle handle) {
   int16_t index = GetIndex(handle);
   std::scoped_lock lock(m_handleMutex);
-  if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
+  if (index < 0 || index >= static_cast<int16_t>(m_structures.size())) {
     return nullptr;
+  }
   return std::move(m_structures[index]);
 }
 
diff --git a/hal/src/main/native/include/hal/simulation/AccelerometerData.h b/hal/src/main/native/include/hal/simulation/AccelerometerData.h
index 0a92671..70cee61 100644
--- a/hal/src/main/native/include/hal/simulation/AccelerometerData.h
+++ b/hal/src/main/native/include/hal/simulation/AccelerometerData.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/include/hal/simulation/AddressableLEDData.h b/hal/src/main/native/include/hal/simulation/AddressableLEDData.h
index 91ab30c..d828e5c 100644
--- a/hal/src/main/native/include/hal/simulation/AddressableLEDData.h
+++ b/hal/src/main/native/include/hal/simulation/AddressableLEDData.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/include/hal/simulation/AnalogGyroData.h b/hal/src/main/native/include/hal/simulation/AnalogGyroData.h
index 91e684e..9527140 100644
--- a/hal/src/main/native/include/hal/simulation/AnalogGyroData.h
+++ b/hal/src/main/native/include/hal/simulation/AnalogGyroData.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/include/hal/simulation/AnalogInData.h b/hal/src/main/native/include/hal/simulation/AnalogInData.h
index 9ab2d3b..2e2d8be 100644
--- a/hal/src/main/native/include/hal/simulation/AnalogInData.h
+++ b/hal/src/main/native/include/hal/simulation/AnalogInData.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/include/hal/simulation/AnalogOutData.h b/hal/src/main/native/include/hal/simulation/AnalogOutData.h
index fa1413d..00275c6 100644
--- a/hal/src/main/native/include/hal/simulation/AnalogOutData.h
+++ b/hal/src/main/native/include/hal/simulation/AnalogOutData.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/include/hal/simulation/AnalogTriggerData.h b/hal/src/main/native/include/hal/simulation/AnalogTriggerData.h
index 74c762c..fb232a2 100644
--- a/hal/src/main/native/include/hal/simulation/AnalogTriggerData.h
+++ b/hal/src/main/native/include/hal/simulation/AnalogTriggerData.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/include/hal/simulation/CTREPCMData.h b/hal/src/main/native/include/hal/simulation/CTREPCMData.h
new file mode 100644
index 0000000..302f7dd
--- /dev/null
+++ b/hal/src/main/native/include/hal/simulation/CTREPCMData.h
@@ -0,0 +1,78 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include "hal/Types.h"
+#include "hal/simulation/NotifyListener.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetCTREPCMData(int32_t index);
+int32_t HALSIM_RegisterCTREPCMInitializedCallback(int32_t index,
+                                                  HAL_NotifyCallback callback,
+                                                  void* param,
+                                                  HAL_Bool initialNotify);
+void HALSIM_CancelCTREPCMInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetCTREPCMInitialized(int32_t index);
+void HALSIM_SetCTREPCMInitialized(int32_t index, HAL_Bool solenoidInitialized);
+
+int32_t HALSIM_RegisterCTREPCMSolenoidOutputCallback(
+    int32_t index, int32_t channel, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelCTREPCMSolenoidOutputCallback(int32_t index, int32_t channel,
+                                                int32_t uid);
+HAL_Bool HALSIM_GetCTREPCMSolenoidOutput(int32_t index, int32_t channel);
+void HALSIM_SetCTREPCMSolenoidOutput(int32_t index, int32_t channel,
+                                     HAL_Bool solenoidOutput);
+
+int32_t HALSIM_RegisterCTREPCMCompressorOnCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelCTREPCMCompressorOnCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetCTREPCMCompressorOn(int32_t index);
+void HALSIM_SetCTREPCMCompressorOn(int32_t index, HAL_Bool compressorOn);
+
+int32_t HALSIM_RegisterCTREPCMClosedLoopEnabledCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelCTREPCMClosedLoopEnabledCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetCTREPCMClosedLoopEnabled(int32_t index);
+void HALSIM_SetCTREPCMClosedLoopEnabled(int32_t index,
+                                        HAL_Bool closedLoopEnabled);
+
+int32_t HALSIM_RegisterCTREPCMPressureSwitchCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelCTREPCMPressureSwitchCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetCTREPCMPressureSwitch(int32_t index);
+void HALSIM_SetCTREPCMPressureSwitch(int32_t index, HAL_Bool pressureSwitch);
+
+int32_t HALSIM_RegisterCTREPCMCompressorCurrentCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelCTREPCMCompressorCurrentCallback(int32_t index, int32_t uid);
+double HALSIM_GetCTREPCMCompressorCurrent(int32_t index);
+void HALSIM_SetCTREPCMCompressorCurrent(int32_t index,
+                                        double compressorCurrent);
+
+void HALSIM_GetCTREPCMAllSolenoids(int32_t index, uint8_t* values);
+void HALSIM_SetCTREPCMAllSolenoids(int32_t index, uint8_t values);
+
+void HALSIM_RegisterCTREPCMAllNonSolenoidCallbacks(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+
+void HALSIM_RegisterCTREPCMAllSolenoidCallbacks(int32_t index, int32_t channel,
+                                                HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/hal/src/main/native/include/hal/simulation/CanData.h b/hal/src/main/native/include/hal/simulation/CanData.h
index eb5ea63..2590162 100644
--- a/hal/src/main/native/include/hal/simulation/CanData.h
+++ b/hal/src/main/native/include/hal/simulation/CanData.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/include/hal/simulation/DIOData.h b/hal/src/main/native/include/hal/simulation/DIOData.h
index ddda655..d2d7181 100644
--- a/hal/src/main/native/include/hal/simulation/DIOData.h
+++ b/hal/src/main/native/include/hal/simulation/DIOData.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/include/hal/simulation/DigitalPWMData.h b/hal/src/main/native/include/hal/simulation/DigitalPWMData.h
index 79428b0..1010811 100644
--- a/hal/src/main/native/include/hal/simulation/DigitalPWMData.h
+++ b/hal/src/main/native/include/hal/simulation/DigitalPWMData.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/include/hal/simulation/DriverStationData.h b/hal/src/main/native/include/hal/simulation/DriverStationData.h
index 536738b..87223ec 100644
--- a/hal/src/main/native/include/hal/simulation/DriverStationData.h
+++ b/hal/src/main/native/include/hal/simulation/DriverStationData.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/include/hal/simulation/DutyCycleData.h b/hal/src/main/native/include/hal/simulation/DutyCycleData.h
index 7b191f28..bbe5bf2 100644
--- a/hal/src/main/native/include/hal/simulation/DutyCycleData.h
+++ b/hal/src/main/native/include/hal/simulation/DutyCycleData.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/include/hal/simulation/EncoderData.h b/hal/src/main/native/include/hal/simulation/EncoderData.h
index 80c142d..df1c12b 100644
--- a/hal/src/main/native/include/hal/simulation/EncoderData.h
+++ b/hal/src/main/native/include/hal/simulation/EncoderData.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/include/hal/simulation/I2CData.h b/hal/src/main/native/include/hal/simulation/I2CData.h
index 3d72850..d5e13f9 100644
--- a/hal/src/main/native/include/hal/simulation/I2CData.h
+++ b/hal/src/main/native/include/hal/simulation/I2CData.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/include/hal/simulation/MockHooks.h b/hal/src/main/native/include/hal/simulation/MockHooks.h
index cef205e..330f72e 100644
--- a/hal/src/main/native/include/hal/simulation/MockHooks.h
+++ b/hal/src/main/native/include/hal/simulation/MockHooks.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
 
@@ -30,4 +27,13 @@
 typedef int32_t (*HALSIM_SendConsoleLineHandler)(const char* line);
 void HALSIM_SetSendConsoleLine(HALSIM_SendConsoleLineHandler handler);
 
+typedef void (*HALSIM_SimPeriodicCallback)(void* param);
+int32_t HALSIM_RegisterSimPeriodicBeforeCallback(
+    HALSIM_SimPeriodicCallback callback, void* param);
+void HALSIM_CancelSimPeriodicBeforeCallback(int32_t uid);
+
+int32_t HALSIM_RegisterSimPeriodicAfterCallback(
+    HALSIM_SimPeriodicCallback callback, void* param);
+void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid);
+
 }  // extern "C"
diff --git a/hal/src/main/native/include/hal/simulation/NotifierData.h b/hal/src/main/native/include/hal/simulation/NotifierData.h
index a5b68b6..13dcf1d 100644
--- a/hal/src/main/native/include/hal/simulation/NotifierData.h
+++ b/hal/src/main/native/include/hal/simulation/NotifierData.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/include/hal/simulation/NotifyListener.h b/hal/src/main/native/include/hal/simulation/NotifyListener.h
index a1430c4..46a93c9 100644
--- a/hal/src/main/native/include/hal/simulation/NotifyListener.h
+++ b/hal/src/main/native/include/hal/simulation/NotifyListener.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/include/hal/simulation/PCMData.h b/hal/src/main/native/include/hal/simulation/PCMData.h
deleted file mode 100644
index ad2188d..0000000
--- a/hal/src/main/native/include/hal/simulation/PCMData.h
+++ /dev/null
@@ -1,92 +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 "hal/Types.h"
-#include "hal/simulation/NotifyListener.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void HALSIM_ResetPCMData(int32_t index);
-int32_t HALSIM_RegisterPCMSolenoidInitializedCallback(
-    int32_t index, int32_t channel, HAL_NotifyCallback callback, void* param,
-    HAL_Bool initialNotify);
-void HALSIM_CancelPCMSolenoidInitializedCallback(int32_t index, int32_t channel,
-                                                 int32_t uid);
-HAL_Bool HALSIM_GetPCMSolenoidInitialized(int32_t index, int32_t channel);
-void HALSIM_SetPCMSolenoidInitialized(int32_t index, int32_t channel,
-                                      HAL_Bool solenoidInitialized);
-
-int32_t HALSIM_RegisterPCMSolenoidOutputCallback(int32_t index, int32_t channel,
-                                                 HAL_NotifyCallback callback,
-                                                 void* param,
-                                                 HAL_Bool initialNotify);
-void HALSIM_CancelPCMSolenoidOutputCallback(int32_t index, int32_t channel,
-                                            int32_t uid);
-HAL_Bool HALSIM_GetPCMSolenoidOutput(int32_t index, int32_t channel);
-void HALSIM_SetPCMSolenoidOutput(int32_t index, int32_t channel,
-                                 HAL_Bool solenoidOutput);
-
-int32_t HALSIM_RegisterPCMCompressorInitializedCallback(
-    int32_t index, HAL_NotifyCallback callback, void* param,
-    HAL_Bool initialNotify);
-void HALSIM_CancelPCMCompressorInitializedCallback(int32_t index, int32_t uid);
-HAL_Bool HALSIM_GetPCMCompressorInitialized(int32_t index);
-void HALSIM_SetPCMCompressorInitialized(int32_t index,
-                                        HAL_Bool compressorInitialized);
-
-int32_t HALSIM_RegisterPCMCompressorOnCallback(int32_t index,
-                                               HAL_NotifyCallback callback,
-                                               void* param,
-                                               HAL_Bool initialNotify);
-void HALSIM_CancelPCMCompressorOnCallback(int32_t index, int32_t uid);
-HAL_Bool HALSIM_GetPCMCompressorOn(int32_t index);
-void HALSIM_SetPCMCompressorOn(int32_t index, HAL_Bool compressorOn);
-
-int32_t HALSIM_RegisterPCMClosedLoopEnabledCallback(int32_t index,
-                                                    HAL_NotifyCallback callback,
-                                                    void* param,
-                                                    HAL_Bool initialNotify);
-void HALSIM_CancelPCMClosedLoopEnabledCallback(int32_t index, int32_t uid);
-HAL_Bool HALSIM_GetPCMClosedLoopEnabled(int32_t index);
-void HALSIM_SetPCMClosedLoopEnabled(int32_t index, HAL_Bool closedLoopEnabled);
-
-int32_t HALSIM_RegisterPCMPressureSwitchCallback(int32_t index,
-                                                 HAL_NotifyCallback callback,
-                                                 void* param,
-                                                 HAL_Bool initialNotify);
-void HALSIM_CancelPCMPressureSwitchCallback(int32_t index, int32_t uid);
-HAL_Bool HALSIM_GetPCMPressureSwitch(int32_t index);
-void HALSIM_SetPCMPressureSwitch(int32_t index, HAL_Bool pressureSwitch);
-
-int32_t HALSIM_RegisterPCMCompressorCurrentCallback(int32_t index,
-                                                    HAL_NotifyCallback callback,
-                                                    void* param,
-                                                    HAL_Bool initialNotify);
-void HALSIM_CancelPCMCompressorCurrentCallback(int32_t index, int32_t uid);
-double HALSIM_GetPCMCompressorCurrent(int32_t index);
-void HALSIM_SetPCMCompressorCurrent(int32_t index, double compressorCurrent);
-
-void HALSIM_GetPCMAllSolenoids(int32_t index, uint8_t* values);
-void HALSIM_SetPCMAllSolenoids(int32_t index, uint8_t values);
-
-void HALSIM_RegisterPCMAllNonSolenoidCallbacks(int32_t index,
-                                               HAL_NotifyCallback callback,
-                                               void* param,
-                                               HAL_Bool initialNotify);
-
-void HALSIM_RegisterPCMAllSolenoidCallbacks(int32_t index, int32_t channel,
-                                            HAL_NotifyCallback callback,
-                                            void* param,
-                                            HAL_Bool initialNotify);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
diff --git a/hal/src/main/native/include/hal/simulation/PDPData.h b/hal/src/main/native/include/hal/simulation/PDPData.h
deleted file mode 100644
index 7ec11a4..0000000
--- a/hal/src/main/native/include/hal/simulation/PDPData.h
+++ /dev/null
@@ -1,59 +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 "hal/Types.h"
-#include "hal/simulation/NotifyListener.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void HALSIM_ResetPDPData(int32_t index);
-int32_t HALSIM_RegisterPDPInitializedCallback(int32_t index,
-                                              HAL_NotifyCallback callback,
-                                              void* param,
-                                              HAL_Bool initialNotify);
-void HALSIM_CancelPDPInitializedCallback(int32_t index, int32_t uid);
-HAL_Bool HALSIM_GetPDPInitialized(int32_t index);
-void HALSIM_SetPDPInitialized(int32_t index, HAL_Bool initialized);
-
-int32_t HALSIM_RegisterPDPTemperatureCallback(int32_t index,
-                                              HAL_NotifyCallback callback,
-                                              void* param,
-                                              HAL_Bool initialNotify);
-void HALSIM_CancelPDPTemperatureCallback(int32_t index, int32_t uid);
-double HALSIM_GetPDPTemperature(int32_t index);
-void HALSIM_SetPDPTemperature(int32_t index, double temperature);
-
-int32_t HALSIM_RegisterPDPVoltageCallback(int32_t index,
-                                          HAL_NotifyCallback callback,
-                                          void* param, HAL_Bool initialNotify);
-void HALSIM_CancelPDPVoltageCallback(int32_t index, int32_t uid);
-double HALSIM_GetPDPVoltage(int32_t index);
-void HALSIM_SetPDPVoltage(int32_t index, double voltage);
-
-int32_t HALSIM_RegisterPDPCurrentCallback(int32_t index, int32_t channel,
-                                          HAL_NotifyCallback callback,
-                                          void* param, HAL_Bool initialNotify);
-void HALSIM_CancelPDPCurrentCallback(int32_t index, int32_t channel,
-                                     int32_t uid);
-double HALSIM_GetPDPCurrent(int32_t index, int32_t channel);
-void HALSIM_SetPDPCurrent(int32_t index, int32_t channel, double current);
-
-void HALSIM_GetPDPAllCurrents(int32_t index, double* currents);
-void HALSIM_SetPDPAllCurrents(int32_t index, const double* currents);
-
-void HALSIM_RegisterPDPAllNonCurrentCallbacks(int32_t index, int32_t channel,
-                                              HAL_NotifyCallback callback,
-                                              void* param,
-                                              HAL_Bool initialNotify);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
diff --git a/hal/src/main/native/include/hal/simulation/PWMData.h b/hal/src/main/native/include/hal/simulation/PWMData.h
index a536710..91d22df 100644
--- a/hal/src/main/native/include/hal/simulation/PWMData.h
+++ b/hal/src/main/native/include/hal/simulation/PWMData.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/include/hal/simulation/PowerDistributionData.h b/hal/src/main/native/include/hal/simulation/PowerDistributionData.h
new file mode 100644
index 0000000..0552c49
--- /dev/null
+++ b/hal/src/main/native/include/hal/simulation/PowerDistributionData.h
@@ -0,0 +1,60 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include "hal/Types.h"
+#include "hal/simulation/NotifyListener.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetPowerDistributionData(int32_t index);
+int32_t HALSIM_RegisterPowerDistributionInitializedCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelPowerDistributionInitializedCallback(int32_t index,
+                                                       int32_t uid);
+HAL_Bool HALSIM_GetPowerDistributionInitialized(int32_t index);
+void HALSIM_SetPowerDistributionInitialized(int32_t index,
+                                            HAL_Bool initialized);
+
+int32_t HALSIM_RegisterPowerDistributionTemperatureCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelPowerDistributionTemperatureCallback(int32_t index,
+                                                       int32_t uid);
+double HALSIM_GetPowerDistributionTemperature(int32_t index);
+void HALSIM_SetPowerDistributionTemperature(int32_t index, double temperature);
+
+int32_t HALSIM_RegisterPowerDistributionVoltageCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelPowerDistributionVoltageCallback(int32_t index, int32_t uid);
+double HALSIM_GetPowerDistributionVoltage(int32_t index);
+void HALSIM_SetPowerDistributionVoltage(int32_t index, double voltage);
+
+int32_t HALSIM_RegisterPowerDistributionCurrentCallback(
+    int32_t index, int32_t channel, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelPowerDistributionCurrentCallback(int32_t index,
+                                                   int32_t channel,
+                                                   int32_t uid);
+double HALSIM_GetPowerDistributionCurrent(int32_t index, int32_t channel);
+void HALSIM_SetPowerDistributionCurrent(int32_t index, int32_t channel,
+                                        double current);
+
+void HALSIM_GetPowerDistributionAllCurrents(int32_t index, double* currents,
+                                            int length);
+void HALSIM_SetPowerDistributionAllCurrents(int32_t index,
+                                            const double* currents, int length);
+
+void HALSIM_RegisterPowerDistributionAllNonCurrentCallbacks(
+    int32_t index, int32_t channel, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/hal/src/main/native/include/hal/simulation/REVPHData.h b/hal/src/main/native/include/hal/simulation/REVPHData.h
new file mode 100644
index 0000000..17e4f2c
--- /dev/null
+++ b/hal/src/main/native/include/hal/simulation/REVPHData.h
@@ -0,0 +1,80 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#pragma once
+
+#include "hal/Types.h"
+#include "hal/simulation/NotifyListener.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void HALSIM_ResetREVPHData(int32_t index);
+int32_t HALSIM_RegisterREVPHInitializedCallback(int32_t index,
+                                                HAL_NotifyCallback callback,
+                                                void* param,
+                                                HAL_Bool initialNotify);
+void HALSIM_CancelREVPHInitializedCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetREVPHInitialized(int32_t index);
+void HALSIM_SetREVPHInitialized(int32_t index, HAL_Bool solenoidInitialized);
+
+int32_t HALSIM_RegisterREVPHSolenoidOutputCallback(int32_t index,
+                                                   int32_t channel,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelREVPHSolenoidOutputCallback(int32_t index, int32_t channel,
+                                              int32_t uid);
+HAL_Bool HALSIM_GetREVPHSolenoidOutput(int32_t index, int32_t channel);
+void HALSIM_SetREVPHSolenoidOutput(int32_t index, int32_t channel,
+                                   HAL_Bool solenoidOutput);
+
+int32_t HALSIM_RegisterREVPHCompressorOnCallback(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+void HALSIM_CancelREVPHCompressorOnCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetREVPHCompressorOn(int32_t index);
+void HALSIM_SetREVPHCompressorOn(int32_t index, HAL_Bool compressorOn);
+
+int32_t HALSIM_RegisterREVPHClosedLoopEnabledCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelREVPHClosedLoopEnabledCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetREVPHClosedLoopEnabled(int32_t index);
+void HALSIM_SetREVPHClosedLoopEnabled(int32_t index,
+                                      HAL_Bool closedLoopEnabled);
+
+int32_t HALSIM_RegisterREVPHPressureSwitchCallback(int32_t index,
+                                                   HAL_NotifyCallback callback,
+                                                   void* param,
+                                                   HAL_Bool initialNotify);
+void HALSIM_CancelREVPHPressureSwitchCallback(int32_t index, int32_t uid);
+HAL_Bool HALSIM_GetREVPHPressureSwitch(int32_t index);
+void HALSIM_SetREVPHPressureSwitch(int32_t index, HAL_Bool pressureSwitch);
+
+int32_t HALSIM_RegisterREVPHCompressorCurrentCallback(
+    int32_t index, HAL_NotifyCallback callback, void* param,
+    HAL_Bool initialNotify);
+void HALSIM_CancelREVPHCompressorCurrentCallback(int32_t index, int32_t uid);
+double HALSIM_GetREVPHCompressorCurrent(int32_t index);
+void HALSIM_SetREVPHCompressorCurrent(int32_t index, double compressorCurrent);
+
+void HALSIM_GetREVPHAllSolenoids(int32_t index, uint8_t* values);
+void HALSIM_SetREVPHAllSolenoids(int32_t index, uint8_t values);
+
+void HALSIM_RegisterREVPHAllNonSolenoidCallbacks(int32_t index,
+                                                 HAL_NotifyCallback callback,
+                                                 void* param,
+                                                 HAL_Bool initialNotify);
+
+void HALSIM_RegisterREVPHAllSolenoidCallbacks(int32_t index, int32_t channel,
+                                              HAL_NotifyCallback callback,
+                                              void* param,
+                                              HAL_Bool initialNotify);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/hal/src/main/native/include/hal/simulation/RelayData.h b/hal/src/main/native/include/hal/simulation/RelayData.h
index 1329d29..d61c9e0 100644
--- a/hal/src/main/native/include/hal/simulation/RelayData.h
+++ b/hal/src/main/native/include/hal/simulation/RelayData.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/include/hal/simulation/RoboRioData.h b/hal/src/main/native/include/hal/simulation/RoboRioData.h
index 49d32f3..8f33bc5 100644
--- a/hal/src/main/native/include/hal/simulation/RoboRioData.h
+++ b/hal/src/main/native/include/hal/simulation/RoboRioData.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
 
@@ -118,6 +115,12 @@
 int32_t HALSIM_GetRoboRioUserFaults3V3(void);
 void HALSIM_SetRoboRioUserFaults3V3(int32_t userFaults3V3);
 
+int32_t HALSIM_RegisterRoboRioBrownoutVoltageCallback(
+    HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify);
+void HALSIM_CancelRoboRioBrownoutVoltageCallback(int32_t uid);
+double HALSIM_GetRoboRioBrownoutVoltage(void);
+void HALSIM_SetRoboRioBrownoutVoltage(double brownoutVoltage);
+
 void HALSIM_RegisterRoboRioAllCallbacks(HAL_NotifyCallback callback,
                                         void* param, HAL_Bool initialNotify);
 
diff --git a/hal/src/main/native/include/hal/simulation/SPIAccelerometerData.h b/hal/src/main/native/include/hal/simulation/SPIAccelerometerData.h
index 6515aa8..406798f 100644
--- a/hal/src/main/native/include/hal/simulation/SPIAccelerometerData.h
+++ b/hal/src/main/native/include/hal/simulation/SPIAccelerometerData.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/include/hal/simulation/SPIData.h b/hal/src/main/native/include/hal/simulation/SPIData.h
index 149a1ef..813b75f 100644
--- a/hal/src/main/native/include/hal/simulation/SPIData.h
+++ b/hal/src/main/native/include/hal/simulation/SPIData.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/include/hal/simulation/SimCallbackRegistry.h b/hal/src/main/native/include/hal/simulation/SimCallbackRegistry.h
index 31f64ef..3d786e0 100644
--- a/hal/src/main/native/include/hal/simulation/SimCallbackRegistry.h
+++ b/hal/src/main/native/include/hal/simulation/SimCallbackRegistry.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -30,7 +27,9 @@
  public:
   void Cancel(int32_t uid) {
     std::scoped_lock lock(m_mutex);
-    if (m_callbacks && uid > 0) m_callbacks->erase(uid - 1);
+    if (m_callbacks && uid > 0) {
+      m_callbacks->erase(uid - 1);
+    }
   }
 
   void Reset() {
@@ -43,13 +42,19 @@
  protected:
   int32_t DoRegister(RawFunctor 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, callback) + 1;
   }
 
   LLVM_ATTRIBUTE_ALWAYS_INLINE void DoReset() {
-    if (m_callbacks) m_callbacks->clear();
+    if (m_callbacks) {
+      m_callbacks->clear();
+    }
   }
 
   mutable wpi::recursive_spinlock m_mutex;
@@ -81,9 +86,10 @@
 #endif
     if (m_callbacks) {
       const char* name = GetName();
-      for (auto&& cb : *m_callbacks)
+      for (auto&& cb : *m_callbacks) {
         reinterpret_cast<CallbackFunction>(cb.callback)(name, cb.param,
                                                         std::forward<U>(u)...);
+      }
     }
   }
 
diff --git a/hal/src/main/native/include/hal/simulation/SimDataValue.h b/hal/src/main/native/include/hal/simulation/SimDataValue.h
index ff333a5..4368a10 100644
--- a/hal/src/main/native/include/hal/simulation/SimDataValue.h
+++ b/hal/src/main/native/include/hal/simulation/SimDataValue.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -31,7 +28,7 @@
     return m_value;
   }
 
-  LLVM_ATTRIBUTE_ALWAYS_INLINE operator T() const { return Get(); }
+  LLVM_ATTRIBUTE_ALWAYS_INLINE operator T() const { return Get(); }  // NOLINT
 
   void Reset(T value) {
     std::scoped_lock lock(m_mutex);
@@ -46,7 +43,9 @@
                              HAL_Bool initialNotify, const char* name) {
     std::unique_lock lock(m_mutex);
     int32_t newUid = DoRegister(reinterpret_cast<RawFunctor>(callback), param);
-    if (newUid == -1) return -1;
+    if (newUid == -1) {
+      return -1;
+    }
     if (initialNotify) {
       // We know that the callback is not null because of earlier null check
       HAL_Value value = MakeValue(m_value);
@@ -62,9 +61,10 @@
       m_value = value;
       if (m_callbacks) {
         HAL_Value halValue = MakeValue(value);
-        for (auto&& cb : *m_callbacks)
+        for (auto&& cb : *m_callbacks) {
           reinterpret_cast<HAL_NotifyCallback>(cb.callback)(name, cb.param,
                                                             &halValue);
+        }
       }
     }
   }
diff --git a/hal/src/main/native/include/hal/simulation/SimDeviceData.h b/hal/src/main/native/include/hal/simulation/SimDeviceData.h
index e702c5c..221263e 100644
--- a/hal/src/main/native/include/hal/simulation/SimDeviceData.h
+++ b/hal/src/main/native/include/hal/simulation/SimDeviceData.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
 
@@ -15,7 +12,7 @@
 
 typedef void (*HALSIM_SimValueCallback)(const char* name, void* param,
                                         HAL_SimValueHandle handle,
-                                        HAL_Bool readonly,
+                                        int32_t direction,
                                         const struct HAL_Value* value);
 
 #ifdef __cplusplus
@@ -31,8 +28,9 @@
 
 void HALSIM_CancelSimDeviceCreatedCallback(int32_t 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);
 
 void HALSIM_CancelSimDeviceFreedCallback(int32_t uid);
 
@@ -59,6 +57,22 @@
 
 void HALSIM_CancelSimValueChangedCallback(int32_t uid);
 
+/**
+ * Register a callback for HAL_SimValueReset(). The callback is called with the
+ * old value.
+ *
+ * @param handle simulated value handle
+ * @param param parameter for callback
+ * @param callback callback
+ * @param initialNotify ignored (present for consistency)
+ */
+int32_t HALSIM_RegisterSimValueResetCallback(HAL_SimValueHandle handle,
+                                             void* param,
+                                             HALSIM_SimValueCallback callback,
+                                             HAL_Bool initialNotify);
+
+void HALSIM_CancelSimValueResetCallback(int32_t uid);
+
 HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device,
                                             const char* name);
 
@@ -68,6 +82,9 @@
 const char** HALSIM_GetSimValueEnumOptions(HAL_SimValueHandle handle,
                                            int32_t* numOptions);
 
+const double* HALSIM_GetSimValueEnumDoubleValues(HAL_SimValueHandle handle,
+                                                 int32_t* numOptions);
+
 void HALSIM_ResetSimDeviceData(void);
 
 #ifdef __cplusplus
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;
diff --git a/hal/src/test/native/cpp/HALTest.cpp b/hal/src/test/native/cpp/HALTest.cpp
new file mode 100644
index 0000000..62a4f85
--- /dev/null
+++ b/hal/src/test/native/cpp/HALTest.cpp
@@ -0,0 +1,12 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+
+namespace hal {
+TEST(HALTest, RuntimeType) {
+  EXPECT_EQ(HAL_RuntimeType::HAL_Runtime_Simulation, HAL_GetRuntimeType());
+}
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/HALTests.cpp b/hal/src/test/native/cpp/HALTests.cpp
deleted file mode 100644
index b387c14..0000000
--- a/hal/src/test/native/cpp/HALTests.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-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 "gtest/gtest.h"
-#include "hal/HAL.h"
-#include "hal/Solenoid.h"
-
-namespace hal {
-TEST(HALTests, RuntimeType) {
-  EXPECT_EQ(HAL_RuntimeType::HAL_Mock, HAL_GetRuntimeType());
-}
-
-TEST(HALSOLENOID, SolenoidTest) {
-  int32_t status = 0;
-  HAL_InitializeSolenoidPort(0, &status);
-  EXPECT_NE(status, 0);
-}
-}  // namespace hal
diff --git a/hal/src/test/native/cpp/can/CANTest.cpp b/hal/src/test/native/cpp/can/CANTest.cpp
index 427bb54..db9dbf5 100644
--- a/hal/src/test/native/cpp/can/CANTest.cpp
+++ b/hal/src/test/native/cpp/can/CANTest.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "gtest/gtest.h"
 #include "hal/CANAPI.h"
@@ -41,7 +38,7 @@
   int32_t handle;
 };
 
-TEST(HALCanTests, CanIdPackingTest) {
+TEST(CANTest, CanIdPacking) {
   int32_t status = 0;
   int32_t deviceId = 12;
   CANTestStore testStore(deviceId, &status);
diff --git a/hal/src/test/native/cpp/handles/HandleTest.cpp b/hal/src/test/native/cpp/handles/HandleTest.cpp
new file mode 100644
index 0000000..5c98f7f
--- /dev/null
+++ b/hal/src/test/native/cpp/handles/HandleTest.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/handles/IndexedClassedHandleResource.h"
+
+#define HAL_TestHandle HAL_Handle
+
+namespace {
+class MyTestClass {};
+}  // namespace
+
+namespace hal {
+TEST(HandleTest, ClassedHandle) {
+  hal::IndexedClassedHandleResource<HAL_TestHandle, MyTestClass, 8,
+                                    HAL_HandleEnum::Vendor>
+      testClass;
+  int32_t status = 0;
+  testClass.Allocate(0, std::make_unique<MyTestClass>(), &status);
+  EXPECT_EQ(0, status);
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/handles/HandleTests.cpp b/hal/src/test/native/cpp/handles/HandleTests.cpp
deleted file mode 100644
index e893c78..0000000
--- a/hal/src/test/native/cpp/handles/HandleTests.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* 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.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "gtest/gtest.h"
-#include "hal/HAL.h"
-#include "hal/handles/IndexedClassedHandleResource.h"
-
-#define HAL_TestHandle HAL_Handle
-
-namespace {
-class MyTestClass {};
-}  // namespace
-
-namespace hal {
-TEST(HandleTests, ClassedHandleTest) {
-  hal::IndexedClassedHandleResource<HAL_TestHandle, MyTestClass, 8,
-                                    HAL_HandleEnum::Vendor>
-      testClass;
-  int32_t status = 0;
-  testClass.Allocate(0, std::make_unique<MyTestClass>(), &status);
-  EXPECT_EQ(0, status);
-}
-
-}  // namespace hal
diff --git a/hal/src/test/native/cpp/main.cpp b/hal/src/test/native/cpp/main.cpp
index 33990f0..7981c04 100644
--- a/hal/src/test/native/cpp/main.cpp
+++ b/hal/src/test/native/cpp/main.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-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 "gtest/gtest.h"
 #include "hal/HAL.h"
diff --git a/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp b/hal/src/test/native/cpp/mockdata/AnalogInDataTest.cpp
similarity index 69%
rename from hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp
rename to hal/src/test/native/cpp/mockdata/AnalogInDataTest.cpp
index c102480..284ebd6 100644
--- a/hal/src/test/native/cpp/mockdata/AnalogInDataTests.cpp
+++ b/hal/src/test/native/cpp/mockdata/AnalogInDataTest.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "gtest/gtest.h"
 #include "hal/AnalogInput.h"
@@ -22,7 +19,7 @@
   gTestAnalogInCallbackValue = *value;
 }
 
-TEST(AnalogInSimTests, TestAnalogInInitialization) {
+TEST(AnalogInSimTest, AnalogInInitialization) {
   const int INDEX_TO_TEST = 1;
 
   int callbackParam = 0;
@@ -31,24 +28,25 @@
       false);
   ASSERT_TRUE(0 != callbackId);
 
-  int32_t status;
+  int32_t status = 0;
   HAL_PortHandle portHandle;
   HAL_DigitalHandle analogInHandle;
 
   // Use out of range index
-  status = 0;
   portHandle = 8000;
   gTestAnalogInCallbackName = "Unset";
-  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status);
+  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, analogInHandle);
-  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
+  EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status);
   EXPECT_STREQ("Unset", gTestAnalogInCallbackName.c_str());
 
   // Successful setup
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestAnalogInCallbackName = "Unset";
-  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status);
+  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != analogInHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("Initialized", gTestAnalogInCallbackName.c_str());
@@ -57,8 +55,10 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestAnalogInCallbackName = "Unset";
-  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status);
+  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, analogInHandle);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
   EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
   EXPECT_STREQ("Unset", gTestAnalogInCallbackName.c_str());
 
@@ -72,9 +72,10 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestAnalogInCallbackName = "Unset";
-  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, &status);
+  analogInHandle = HAL_InitializeAnalogInputPort(portHandle, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != analogInHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("Initialized", gTestAnalogInCallbackName.c_str());
+  HALSIM_CancelAnalogInInitializedCallback(INDEX_TO_TEST, callbackId);
 }
 }  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp b/hal/src/test/native/cpp/mockdata/AnalogOutDataTest.cpp
similarity index 69%
rename from hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp
rename to hal/src/test/native/cpp/mockdata/AnalogOutDataTest.cpp
index d6c9f70..15a5fa6 100644
--- a/hal/src/test/native/cpp/mockdata/AnalogOutDataTests.cpp
+++ b/hal/src/test/native/cpp/mockdata/AnalogOutDataTest.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "gtest/gtest.h"
 #include "hal/AnalogOutput.h"
@@ -22,7 +19,7 @@
   gTestAnalogOutCallbackValue = *value;
 }
 
-TEST(AnalogOutSimTests, TestAnalogOutInitialization) {
+TEST(AnalogOutSimTest, AnalogOutInitialization) {
   const int INDEX_TO_TEST = 1;
 
   int callbackParam = 0;
@@ -31,24 +28,27 @@
       false);
   ASSERT_TRUE(0 != callbackId);
 
-  int32_t status;
+  int32_t status = 0;
   HAL_PortHandle portHandle;
   HAL_DigitalHandle analogOutHandle;
 
   // Use out of range index
-  status = 0;
   portHandle = 8000;
   gTestAnalogOutCallbackName = "Unset";
-  analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status);
+  analogOutHandle =
+      HAL_InitializeAnalogOutputPort(portHandle, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, analogOutHandle);
-  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
+  EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status);
   EXPECT_STREQ("Unset", gTestAnalogOutCallbackName.c_str());
 
   // Successful setup
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestAnalogOutCallbackName = "Unset";
-  analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status);
+  analogOutHandle =
+      HAL_InitializeAnalogOutputPort(portHandle, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != analogOutHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("Initialized", gTestAnalogOutCallbackName.c_str());
@@ -57,8 +57,11 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestAnalogOutCallbackName = "Unset";
-  analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status);
+  analogOutHandle =
+      HAL_InitializeAnalogOutputPort(portHandle, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, analogOutHandle);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
   EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
   EXPECT_STREQ("Unset", gTestAnalogOutCallbackName.c_str());
 
@@ -72,9 +75,11 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestAnalogOutCallbackName = "Unset";
-  analogOutHandle = HAL_InitializeAnalogOutputPort(portHandle, &status);
+  analogOutHandle =
+      HAL_InitializeAnalogOutputPort(portHandle, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != analogOutHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("Initialized", gTestAnalogOutCallbackName.c_str());
+  HALSIM_CancelAnalogOutInitializedCallback(INDEX_TO_TEST, callbackId);
 }
 }  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/DIODataTests.cpp b/hal/src/test/native/cpp/mockdata/DIODataTest.cpp
similarity index 69%
rename from hal/src/test/native/cpp/mockdata/DIODataTests.cpp
rename to hal/src/test/native/cpp/mockdata/DIODataTest.cpp
index 248f841..e8ab350 100644
--- a/hal/src/test/native/cpp/mockdata/DIODataTests.cpp
+++ b/hal/src/test/native/cpp/mockdata/DIODataTest.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "gtest/gtest.h"
 #include "hal/DIO.h"
@@ -22,7 +19,7 @@
   gTestDigitalIoCallbackValue = *value;
 }
 
-TEST(DigitalIoSimTests, TestDigitalIoInitialization) {
+TEST(DigitalIoSimTest, DigitalIoInitialization) {
   const int INDEX_TO_TEST = 3;
 
   int callbackParam = 0;
@@ -31,24 +28,25 @@
       false);
   ASSERT_TRUE(0 != callbackId);
 
-  int32_t status;
+  int32_t status = 0;
   HAL_PortHandle portHandle;
   HAL_DigitalHandle digitalIoHandle;
 
   // Use out of range index
-  status = 0;
   portHandle = 8000;
   gTestDigitalIoCallbackName = "Unset";
-  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status);
+  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, digitalIoHandle);
-  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
+  EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status);
   EXPECT_STREQ("Unset", gTestDigitalIoCallbackName.c_str());
 
   // Successful setup
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestDigitalIoCallbackName = "Unset";
-  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status);
+  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != digitalIoHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("Initialized", gTestDigitalIoCallbackName.c_str());
@@ -57,8 +55,10 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestDigitalIoCallbackName = "Unset";
-  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status);
+  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, digitalIoHandle);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
   EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
   EXPECT_STREQ("Unset", gTestDigitalIoCallbackName.c_str());
 
@@ -72,10 +72,11 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestDigitalIoCallbackName = "Unset";
-  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, &status);
+  digitalIoHandle = HAL_InitializeDIOPort(portHandle, true, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != digitalIoHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("Initialized", gTestDigitalIoCallbackName.c_str());
+  HALSIM_CancelDIOInitializedCallback(INDEX_TO_TEST, callbackId);
 }
 
 }  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/DriverStationDataTests.cpp b/hal/src/test/native/cpp/mockdata/DriverStationDataTest.cpp
similarity index 87%
rename from hal/src/test/native/cpp/mockdata/DriverStationDataTests.cpp
rename to hal/src/test/native/cpp/mockdata/DriverStationDataTest.cpp
index 5cb28c4..4925e16 100644
--- a/hal/src/test/native/cpp/mockdata/DriverStationDataTests.cpp
+++ b/hal/src/test/native/cpp/mockdata/DriverStationDataTest.cpp
@@ -1,20 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include <cstring>
 
 #include "gtest/gtest.h"
 #include "hal/HAL.h"
-#include "hal/Solenoid.h"
 #include "hal/simulation/DriverStationData.h"
 
 namespace hal {
 
-TEST(DriverStationTests, JoystickTests) {
+TEST(DriverStationTest, Joystick) {
   HAL_JoystickAxes axes;
   HAL_JoystickPOVs povs;
   HAL_JoystickButtons buttons;
@@ -113,7 +109,7 @@
   }
 }
 
-TEST(DriverStationTests, EventInfoTest) {
+TEST(DriverStationTest, EventInfo) {
   std::string eventName = "UnitTest";
   std::string gameData = "Insert game specific info here :D";
   HAL_MatchInfo info;
diff --git a/hal/src/test/native/cpp/mockdata/I2CDataTests.cpp b/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp
similarity index 60%
rename from hal/src/test/native/cpp/mockdata/I2CDataTests.cpp
rename to hal/src/test/native/cpp/mockdata/I2CDataTest.cpp
index b78564b..7678a4a 100644
--- a/hal/src/test/native/cpp/mockdata/I2CDataTests.cpp
+++ b/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "gtest/gtest.h"
 #include "hal/HAL.h"
@@ -22,10 +19,10 @@
   gTestI2CCallbackValue = *value;
 }
 
-TEST(I2CSimTests, TestI2CInitialization) {
+TEST(I2CSimTest, I2CInitialization) {
   const int INDEX_TO_TEST = 1;
 
-  int32_t status;
+  int32_t status = 0;
   HAL_I2CPort port;
 
   int callbackParam = 0;
@@ -33,7 +30,6 @@
       INDEX_TO_TEST, &TestI2CInitializationCallback, &callbackParam, false);
   ASSERT_TRUE(0 != callbackId);
 
-  status = 0;
   port = HAL_I2C_kMXP;
   gTestI2CCallbackName = "Unset";
   HAL_InitializeI2C(port, &status);
diff --git a/hal/src/test/native/cpp/mockdata/PCMDataTest.cpp b/hal/src/test/native/cpp/mockdata/PCMDataTest.cpp
new file mode 100644
index 0000000..58a94c0
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/PCMDataTest.cpp
@@ -0,0 +1,82 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "gtest/gtest.h"
+#include "hal/CTREPCM.h"
+#include "hal/HAL.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/simulation/CTREPCMData.h"
+
+namespace hal {
+
+std::string gTestSolenoidCallbackName;
+HAL_Value gTestSolenoidCallbackValue;
+
+void TestSolenoidInitializationCallback(const char* name, void* param,
+                                        const struct HAL_Value* value) {
+  gTestSolenoidCallbackName = name;
+  gTestSolenoidCallbackValue = *value;
+}
+
+TEST(PCMDataTest, PCMInitialization) {
+  const int MODULE_TO_TEST = 2;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterCTREPCMInitializedCallback(
+      MODULE_TO_TEST, &TestSolenoidInitializationCallback, &callbackParam,
+      false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status = 0;
+  int32_t module;
+  HAL_CTREPCMHandle pcmHandle;
+
+  // Use out of range index
+  module = 8000;
+  gTestSolenoidCallbackName = "Unset";
+  pcmHandle = HAL_InitializeCTREPCM(module, nullptr, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, pcmHandle);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
+  EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status);
+  EXPECT_STREQ("Unset", gTestSolenoidCallbackName.c_str());
+
+  // Successful setup
+  status = 0;
+  module = MODULE_TO_TEST;
+  gTestSolenoidCallbackName = "Unset";
+  pcmHandle = HAL_InitializeCTREPCM(module, nullptr, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != pcmHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestSolenoidCallbackName.c_str());
+
+  // Double initialize... should fail
+  status = 0;
+  module = MODULE_TO_TEST;
+  gTestSolenoidCallbackName = "Unset";
+  pcmHandle = HAL_InitializeCTREPCM(module, nullptr, &status);
+  EXPECT_EQ(HAL_kInvalidHandle, pcmHandle);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
+  EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
+  EXPECT_STREQ("Unset", gTestSolenoidCallbackName.c_str());
+
+  // Reset, should allow you to re-register
+  hal::HandleBase::ResetGlobalHandles();
+  HALSIM_ResetCTREPCMData(MODULE_TO_TEST);
+  callbackId = HALSIM_RegisterCTREPCMInitializedCallback(
+      MODULE_TO_TEST, &TestSolenoidInitializationCallback, &callbackParam,
+      false);
+  ASSERT_TRUE(0 != callbackId);
+
+  status = 0;
+  module = MODULE_TO_TEST;
+  gTestSolenoidCallbackName = "Unset";
+  pcmHandle = HAL_InitializeCTREPCM(module, nullptr, &status);
+  EXPECT_TRUE(HAL_kInvalidHandle != pcmHandle);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestSolenoidCallbackName.c_str());
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/PCMDataTests.cpp b/hal/src/test/native/cpp/mockdata/PCMDataTests.cpp
deleted file mode 100644
index 5fc19aa..0000000
--- a/hal/src/test/native/cpp/mockdata/PCMDataTests.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "gtest/gtest.h"
-#include "hal/HAL.h"
-#include "hal/Solenoid.h"
-#include "hal/handles/HandlesInternal.h"
-#include "hal/simulation/PCMData.h"
-
-namespace hal {
-
-std::string gTestSolenoidCallbackName;
-HAL_Value gTestSolenoidCallbackValue;
-
-void TestSolenoidInitializationCallback(const char* name, void* param,
-                                        const struct HAL_Value* value) {
-  gTestSolenoidCallbackName = name;
-  gTestSolenoidCallbackValue = *value;
-}
-
-TEST(SolenoidSimTests, TestSolenoidInitialization) {
-  const int MODULE_TO_TEST = 2;
-  const int CHANNEL_TO_TEST = 3;
-
-  int callbackParam = 0;
-  int callbackId = HALSIM_RegisterPCMSolenoidInitializedCallback(
-      MODULE_TO_TEST, CHANNEL_TO_TEST, &TestSolenoidInitializationCallback,
-      &callbackParam, false);
-  ASSERT_TRUE(0 != callbackId);
-
-  int32_t status;
-  HAL_PortHandle portHandle;
-  HAL_DigitalHandle solenoidHandle;
-
-  // Use out of range index
-  status = 0;
-  portHandle = 8000;
-  gTestSolenoidCallbackName = "Unset";
-  solenoidHandle = HAL_InitializeSolenoidPort(portHandle, &status);
-  EXPECT_EQ(HAL_kInvalidHandle, solenoidHandle);
-  EXPECT_EQ(HAL_HANDLE_ERROR, status);
-  EXPECT_STREQ("Unset", gTestSolenoidCallbackName.c_str());
-
-  // Successful setup
-  status = 0;
-  portHandle = HAL_GetPortWithModule(MODULE_TO_TEST, CHANNEL_TO_TEST);
-  gTestSolenoidCallbackName = "Unset";
-  solenoidHandle = HAL_InitializeSolenoidPort(portHandle, &status);
-  EXPECT_TRUE(HAL_kInvalidHandle != solenoidHandle);
-  EXPECT_EQ(0, status);
-  EXPECT_STREQ("SolenoidInitialized", gTestSolenoidCallbackName.c_str());
-
-  // Double initialize... should fail
-  status = 0;
-  portHandle = HAL_GetPortWithModule(MODULE_TO_TEST, CHANNEL_TO_TEST);
-  gTestSolenoidCallbackName = "Unset";
-  solenoidHandle = HAL_InitializeSolenoidPort(portHandle, &status);
-  EXPECT_EQ(HAL_kInvalidHandle, solenoidHandle);
-  EXPECT_EQ(NO_AVAILABLE_RESOURCES, status);
-  EXPECT_STREQ("Unset", gTestSolenoidCallbackName.c_str());
-
-  // Reset, should allow you to re-register
-  hal::HandleBase::ResetGlobalHandles();
-  HALSIM_ResetPCMData(MODULE_TO_TEST);
-  callbackId = HALSIM_RegisterPCMSolenoidInitializedCallback(
-      MODULE_TO_TEST, CHANNEL_TO_TEST, &TestSolenoidInitializationCallback,
-      &callbackParam, false);
-  ASSERT_TRUE(0 != callbackId);
-
-  status = 0;
-  portHandle = HAL_GetPortWithModule(MODULE_TO_TEST, CHANNEL_TO_TEST);
-  gTestSolenoidCallbackName = "Unset";
-  solenoidHandle = HAL_InitializeSolenoidPort(portHandle, &status);
-  EXPECT_TRUE(HAL_kInvalidHandle != solenoidHandle);
-  EXPECT_EQ(0, status);
-  EXPECT_STREQ("SolenoidInitialized", gTestSolenoidCallbackName.c_str());
-}
-
-}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/PDPDataTest.cpp b/hal/src/test/native/cpp/mockdata/PDPDataTest.cpp
new file mode 100644
index 0000000..59b3ea4
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/PDPDataTest.cpp
@@ -0,0 +1,40 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "gtest/gtest.h"
+#include "hal/HAL.h"
+#include "hal/PowerDistribution.h"
+#include "hal/handles/HandlesInternal.h"
+#include "hal/simulation/PowerDistributionData.h"
+
+namespace hal {
+
+std::string gTestPdpCallbackName;
+HAL_Value gTestPdpCallbackValue;
+
+void TestPdpInitializationCallback(const char* name, void* param,
+                                   const struct HAL_Value* value) {
+  gTestPdpCallbackName = name;
+  gTestPdpCallbackValue = *value;
+}
+
+TEST(PdpSimTest, PdpInitialization) {
+  const int INDEX_TO_TEST = 1;
+
+  int callbackParam = 0;
+  int callbackId = HALSIM_RegisterPowerDistributionInitializedCallback(
+      INDEX_TO_TEST, &TestPdpInitializationCallback, &callbackParam, false);
+  ASSERT_TRUE(0 != callbackId);
+
+  int32_t status = 0;
+
+  // Use out of range index
+  gTestPdpCallbackName = "Unset";
+  HAL_InitializePowerDistribution(
+      INDEX_TO_TEST, HAL_PowerDistributionType_kCTRE, nullptr, &status);
+  EXPECT_EQ(0, status);
+  EXPECT_STREQ("Initialized", gTestPdpCallbackName.c_str());
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/PDPDataTests.cpp b/hal/src/test/native/cpp/mockdata/PDPDataTests.cpp
deleted file mode 100644
index f980c7c..0000000
--- a/hal/src/test/native/cpp/mockdata/PDPDataTests.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "gtest/gtest.h"
-#include "hal/HAL.h"
-#include "hal/PDP.h"
-#include "hal/handles/HandlesInternal.h"
-#include "hal/simulation/PDPData.h"
-
-namespace hal {
-
-std::string gTestPdpCallbackName;
-HAL_Value gTestPdpCallbackValue;
-
-void TestPdpInitializationCallback(const char* name, void* param,
-                                   const struct HAL_Value* value) {
-  gTestPdpCallbackName = name;
-  gTestPdpCallbackValue = *value;
-}
-
-TEST(PdpSimTests, TestPdpInitialization) {
-  const int INDEX_TO_TEST = 1;
-
-  int callbackParam = 0;
-  int callbackId = HALSIM_RegisterPDPInitializedCallback(
-      INDEX_TO_TEST, &TestPdpInitializationCallback, &callbackParam, false);
-  ASSERT_TRUE(0 != callbackId);
-
-  int32_t status;
-
-  // Use out of range index
-  status = 0;
-  gTestPdpCallbackName = "Unset";
-  HAL_InitializePDP(INDEX_TO_TEST, &status);
-  EXPECT_EQ(0, status);
-  EXPECT_STREQ("Initialized", gTestPdpCallbackName.c_str());
-}
-
-}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp b/hal/src/test/native/cpp/mockdata/PWMDataTest.cpp
similarity index 69%
rename from hal/src/test/native/cpp/mockdata/PWMDataTests.cpp
rename to hal/src/test/native/cpp/mockdata/PWMDataTest.cpp
index daca364..ab14704 100644
--- a/hal/src/test/native/cpp/mockdata/PWMDataTests.cpp
+++ b/hal/src/test/native/cpp/mockdata/PWMDataTest.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "gtest/gtest.h"
 #include "hal/HAL.h"
@@ -22,7 +19,7 @@
   gTestPwmCallbackValue = *value;
 }
 
-TEST(PWMSimTests, TestPwmInitialization) {
+TEST(PWMSimTest, PwmInitialization) {
   const int INDEX_TO_TEST = 7;
 
   int callbackParam = 0;
@@ -30,24 +27,25 @@
       INDEX_TO_TEST, &TestPwmInitializationCallback, &callbackParam, false);
   ASSERT_TRUE(0 != callbackId);
 
-  int32_t status;
+  int32_t status = 0;
   HAL_PortHandle portHandle;
   HAL_DigitalHandle pwmHandle;
 
   // Use out of range index
-  status = 0;
   portHandle = 8000;
   gTestPwmCallbackName = "Unset";
-  pwmHandle = HAL_InitializePWMPort(portHandle, &status);
+  pwmHandle = HAL_InitializePWMPort(portHandle, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, pwmHandle);
-  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
+  EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status);
   EXPECT_STREQ("Unset", gTestPwmCallbackName.c_str());
 
   // Successful setup
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestPwmCallbackName = "Unset";
-  pwmHandle = HAL_InitializePWMPort(portHandle, &status);
+  pwmHandle = HAL_InitializePWMPort(portHandle, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != pwmHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("Initialized", gTestPwmCallbackName.c_str());
@@ -56,8 +54,10 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestPwmCallbackName = "Unset";
-  pwmHandle = HAL_InitializePWMPort(portHandle, &status);
+  pwmHandle = HAL_InitializePWMPort(portHandle, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, pwmHandle);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
   EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
   EXPECT_STREQ("Unset", gTestPwmCallbackName.c_str());
 
@@ -70,9 +70,10 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestPwmCallbackName = "Unset";
-  pwmHandle = HAL_InitializePWMPort(portHandle, &status);
+  pwmHandle = HAL_InitializePWMPort(portHandle, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != pwmHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("Initialized", gTestPwmCallbackName.c_str());
+  HALSIM_CancelPWMInitializedCallback(INDEX_TO_TEST, callbackId);
 }
 }  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp b/hal/src/test/native/cpp/mockdata/RelayDataTest.cpp
similarity index 69%
rename from hal/src/test/native/cpp/mockdata/RelayDataTests.cpp
rename to hal/src/test/native/cpp/mockdata/RelayDataTest.cpp
index edc0fb4..eef8631 100644
--- a/hal/src/test/native/cpp/mockdata/RelayDataTests.cpp
+++ b/hal/src/test/native/cpp/mockdata/RelayDataTest.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "gtest/gtest.h"
 #include "hal/HAL.h"
@@ -22,7 +19,7 @@
   gTestRelayCallbackValue = *value;
 }
 
-TEST(RelaySimTests, TestRelayInitialization) {
+TEST(RelaySimTest, RelayInitialization) {
   const int INDEX_TO_TEST = 3;
 
   int callbackParam = 0;
@@ -30,24 +27,25 @@
       INDEX_TO_TEST, &TestRelayInitializationCallback, &callbackParam, false);
   ASSERT_TRUE(0 != callbackId);
 
-  int32_t status;
+  int32_t status = 0;
   HAL_PortHandle portHandle;
   HAL_DigitalHandle pdpHandle;
 
   // Use out of range index
-  status = 0;
   portHandle = 8000;
   gTestRelayCallbackName = "Unset";
-  pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status);
+  pdpHandle = HAL_InitializeRelayPort(portHandle, true, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, pdpHandle);
-  EXPECT_EQ(PARAMETER_OUT_OF_RANGE, status);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
+  EXPECT_EQ(RESOURCE_OUT_OF_RANGE, status);
   EXPECT_STREQ("Unset", gTestRelayCallbackName.c_str());
 
   // Successful setup
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestRelayCallbackName = "Unset";
-  pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status);
+  pdpHandle = HAL_InitializeRelayPort(portHandle, true, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != pdpHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("InitializedForward", gTestRelayCallbackName.c_str());
@@ -56,8 +54,10 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestRelayCallbackName = "Unset";
-  pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status);
+  pdpHandle = HAL_InitializeRelayPort(portHandle, true, nullptr, &status);
   EXPECT_EQ(HAL_kInvalidHandle, pdpHandle);
+  EXPECT_EQ(HAL_USE_LAST_ERROR, status);
+  HAL_GetLastError(&status);
   EXPECT_EQ(RESOURCE_IS_ALLOCATED, status);
   EXPECT_STREQ("Unset", gTestRelayCallbackName.c_str());
 
@@ -70,10 +70,11 @@
   status = 0;
   portHandle = HAL_GetPort(INDEX_TO_TEST);
   gTestRelayCallbackName = "Unset";
-  pdpHandle = HAL_InitializeRelayPort(portHandle, true, &status);
+  pdpHandle = HAL_InitializeRelayPort(portHandle, true, nullptr, &status);
   EXPECT_TRUE(HAL_kInvalidHandle != pdpHandle);
   EXPECT_EQ(0, status);
   EXPECT_STREQ("InitializedForward", gTestRelayCallbackName.c_str());
+  HALSIM_CancelRelayInitializedForwardCallback(INDEX_TO_TEST, callbackId);
 }
 
 }  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/SPIDataTests.cpp b/hal/src/test/native/cpp/mockdata/SPIDataTest.cpp
similarity index 60%
rename from hal/src/test/native/cpp/mockdata/SPIDataTests.cpp
rename to hal/src/test/native/cpp/mockdata/SPIDataTest.cpp
index 423db6d..c427eaf 100644
--- a/hal/src/test/native/cpp/mockdata/SPIDataTests.cpp
+++ b/hal/src/test/native/cpp/mockdata/SPIDataTest.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "gtest/gtest.h"
 #include "hal/HAL.h"
@@ -22,10 +19,10 @@
   gTestSpiCallbackValue = *value;
 }
 
-TEST(SpiSimTests, TestSpiInitialization) {
+TEST(SpiSimTest, SpiInitialization) {
   const int INDEX_TO_TEST = 2;
 
-  int32_t status;
+  int32_t status = 0;
   HAL_SPIPort port;
 
   int callbackParam = 0;
@@ -33,7 +30,6 @@
       INDEX_TO_TEST, &TestSpiInitializationCallback, &callbackParam, false);
   ASSERT_TRUE(0 != callbackId);
 
-  status = 0;
   port = HAL_SPI_kOnboardCS2;
   gTestSpiCallbackName = "Unset";
   HAL_InitializeSPI(port, &status);
diff --git a/hal/src/test/native/cpp/mockdata/SimDeviceDataTest.cpp b/hal/src/test/native/cpp/mockdata/SimDeviceDataTest.cpp
new file mode 100644
index 0000000..1203fd7
--- /dev/null
+++ b/hal/src/test/native/cpp/mockdata/SimDeviceDataTest.cpp
@@ -0,0 +1,22 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+
+#include "gtest/gtest.h"
+#include "hal/SimDevice.h"
+#include "hal/simulation/SimDeviceData.h"
+
+namespace hal {
+
+TEST(SimDeviceSimTest, Enabled) {
+  ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("foo"));
+  HALSIM_SetSimDeviceEnabled("f", false);
+  HALSIM_SetSimDeviceEnabled("foob", true);
+  ASSERT_FALSE(HALSIM_IsSimDeviceEnabled("foo"));
+  ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("foobar"));
+  ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("bar"));
+
+  ASSERT_EQ(HAL_CreateSimDevice("foo"), 0);
+}
+
+}  // namespace hal
diff --git a/hal/src/test/native/cpp/mockdata/SimDeviceDataTests.cpp b/hal/src/test/native/cpp/mockdata/SimDeviceDataTests.cpp
deleted file mode 100644
index 8f65f5c..0000000
--- a/hal/src/test/native/cpp/mockdata/SimDeviceDataTests.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2020 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
-
-#include "gtest/gtest.h"
-#include "hal/SimDevice.h"
-#include "hal/simulation/SimDeviceData.h"
-
-namespace hal {
-
-TEST(SimDeviceSimTests, TestEnabled) {
-  ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("foo"));
-  HALSIM_SetSimDeviceEnabled("f", false);
-  HALSIM_SetSimDeviceEnabled("foob", true);
-  ASSERT_FALSE(HALSIM_IsSimDeviceEnabled("foo"));
-  ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("foobar"));
-  ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("bar"));
-
-  ASSERT_EQ(HAL_CreateSimDevice("foo"), 0);
-}
-
-}  // namespace hal