Squashed 'third_party/allwpilib/' changes from 66b57f032..e473a00f9

e473a00f9 [wpiutil] Base64: Add unsigned span/vector variants (#3702)
52f2d580e [wpiutil] raw_uv_ostream: Add reset() (#3701)
d7b1e3576 [wpiutil] WebSocket: move std::function (#3700)
93799fbe9 [examples] Fix description of TrapezoidProfileSubsystem (#3699)
b84644740 [wpimath] Document pose estimator states, inputs, and outputs (#3698)
2dc35c139 [wpimath] Fix classpaths for JNI class loads (#3697)
2cb171f6f [docs] Set Doxygen extract_all to true and fix Doxygen failures (#3695)
a939cd9c8 [wpimath] Print uncontrollable/unobservable models in LQR and KF (#3694)
d5270d113 [wpimath] Clean up C++ StateSpaceUtil tests (#3692)
b20903960 [wpimath] Remove redundant discretization tests from StateSpaceUtilTest (#3689)
c0cb545b4 [wpilibc] Add deprecated Doxygen attribute to SpeedController (#3691)
35c9f66a7 [wpilib] Rename PneumaticsHub to PneumaticHub (#3686)
796d03d10 [wpiutil] Remove unused LLVM header (#3688)
8723caf78 [wpilibj] Make Java TrapezoidProfile.Constraints an immutable class (#3687)
187f50a34 [wpimath] Catch incorrect parameters to state-space models earlier (#3680)
8d04606c4 Replace instances of frc-characterization with SysId (NFC) (#3681)
b82d4f6e5 [hal, cscore, ntcore] Use WPI common handle type base
87e34967e [wpiutil] Add synchronization primitives
e32499c54 [wpiutil] Add ParallelTcpConnector (#3655)
aa0b49228 [wpilib] Remove redundant "quick turn" docs for curvature drive (NFC) (#3674)
57301a7f9 [hal] REVPH: Start closed-loop compressor control on init (#3673)
d1842ea8f [wpilib] Improve interrupt docs (NFC) (#3679)
558151061 [wpiutil] Add DsClient (#3654)
181723e57 Replace `.to<double>()` and `.template to<double>()` with `.value()` (#3667)
6bc1db44b [commands] Add pointer overload of AddRequirements (artf6003) (#3669)
737b57ed5 [wpimath] Update to drake v0.35.0 (#3665)
4d287d1ae [build] Upgrade WPIJREArtifact to JRE 2022-11.0.12u5 (#3666)
f26eb5ada [hal] Fix another typo (get -> gets) (NFC) (#3663)
94ed275ba [hal] Fix misspelling (numer -> number) (NFC) (#3662)
ac2f44da3 [wpiutil] uv: use move for std::function (#3653)
75fa1fbfb [wpiutil] json::serializer: Optimize construction (#3647)
5e689faea [wpiutil] Import MessagePack implementation (mpack) (#3650)
649a50b40 [wpiutil] Add LEB128 byte-by-byte reader (#3652)
e94397a97 [wpiutil] Move json_serializer.h to public headers (#3646)
4ec58724d [wpiutil] uv::Tcp: Clarify SetNoDelay documentation (#3649)
8cb294aa4 [wpiutil] WebSocket: Make Shutdown() public (#3651)
2b3a9a52b [wpiutil] json: Fix map iterator key() for std::string_view (#3645)
138cbb94b [wpiutil] uv::Async: Add direct call for no-parameter specialization (#3648)
e56d6dea8 [ci] Update testbench pool image to ubuntu-latest (#3643)
43f30e44e [build] Enable comments in doxygen source files (#3644)
9e6db17ef [build] Enable doxygen preprocessor expansion of WPI_DEPRECATED (#3642)
0e631ad2f Add WPILib version to issue template (#3641)
6229d8d2f [build] Docs: set case_sense_names to false (#3392)
4647d09b5 [docs] Fix Doxygen warnings, add CI docs lint job (#3639)
4ad3a5402 [hal] Fix PWM allocation channel (#3637)
05e5feac4 [docs] Fix brownout docs (NFC) (#3638)
67df469c5 [examples] Remove old command-based templates and examples (#3263)
689e9ccfb [hal, wpilib] Add brownout voltage configuration (#3632)
9cd4bc407 [docs] Add useLocal to avoid using installer artifacts (#3634)
61996c2bb [cscore] Fix Java direct callback notifications (#3631)
6d3dd99eb [build] Update to newest native-utils (#3633)
f0b484892 [wpiutil] Fix StringMap iterator equality check (#3629)
8352cbb7a Update development build instructions for 2022 (#3616)
6da08b71d [examples] Fix Intermediate Vision Java Example description (#3628)
5d99059bf [wpiutil] Remove optional.h (#3627)
fa41b106a [glass, wpiutil] Add missing format args (#3626)
4e3fd7d42 [build] Enable Zc:__cplusplus for Windows (#3625)
791d8354d [build] Suppress deprecation/removal warnings for old commands (#3618)
10f19e6fc [hal, wpilib] Add REV PneumaticsHub (#3600)
4c61a1305 [ntcore] Revert to per-element copy for toNative() (#3621)
7b3f62244 [wpiutil] SendableRegistry: Print exception stacktrace (#3620)
d347928e4 [hal] Use better error for when console out is enabled while attempting to use onboard serial port (#3622)
cc31079a1 [hal] Use setcap instead of setuid for setting thread priorities (#3613)
4676648b7 [wpimath] Upgrade to Drake v0.34.0 (#3607)
c7594c911 [build] Allow building wpilibc in cmake without cscore and opencv (#3605)
173cb7359 [wpilib] Add TimesliceRobot (#3502)
af295879f [hal] Set error status for I2C port out of range (#3603)
95dd20a15 [build] Enable spotbugs (#3601)
b65fce86b [wpilib] Remove Timer lock in wpilibj and update docs (#3602)
3b8d3bbcb Remove unused and add missing deprecated.h includes (#3599)
f9e976467 [examples] Rename DriveTrain classes to Drivetrain (#3594)
118a27be2 [wpilib] Add Timer tests (#3595)
59c89428e [wpilib] Deprecate Timer::HasPeriodPassed() (#3598)
202ca5e78 Force C++17 in .clang-format (#3597)
d6f185d8e Rename tests for consistency (#3592)
54ca474db [ci] Enable asan and tsan in CI for tests that pass (#3591)
1ca383b23 Add Debouncer (#3590)
179fde3a7 [build] Update to 2022 native utils and gradle 7 (#3588)
50198ffcf [examples] Add Mechanism2d visualization to Elevator Sim (#3587)
a446c2559 [examples] Synchronize C++ and Java Mechanism2d examples (#3589)
a7fb83103 [ci] clang-tidy: Generate compilation commands DB with Gradle (#3585)
4f5e0c9f8 [examples] Update ArmSimulation example to use Mechanism2d (#3572)
8164b91dc [CI] Print CMake test output on failure (#3583)
4d5fca27e [wpilib] Impove Mechanism2D documentation (NFC) (#3584)
fe59e4b9f Make C++ test names more consistent (#3586)
5c8868549 [wpilibc] Fix C++ MechanisimRoot2D to use same NT entries as Java/Glass (#3582)
9359431ba [wpimath] Clean up Eigen usage
72716f51c [wpimath] Upgrade to Eigen 3.4
382deef75 [wpimath] Explicitly export wpimath symbols
161e21173 [ntcore] Match standard handle layout, only allow 16 instances (#3577)
263a24811 [wpimath] Use jinja for codegen (#3574)
725251d29 [wpilib] Increase tolerances of DifferentialDriveSimTest (#3581)
4dff87301 [wpimath] Make LinearFilter::Factorial() constexpr (#3579)
60ede67ab [hal, wpilib] Switch PCM to be a single object that is allowed to be duplicated (#3475)
906bfc846 [build] Add CMake build support for sanitizers (#3576)
0d4f08ad9 [hal] Simplify string copy of joystick name (#3575)
a52bf87b7 [wpiutil] Add Java function package (#3570)
40c7645d6 [wpiutil] UidVector: Return old object from erase() (#3571)
5b886a23f [wpiutil] jni_util: Add size, operator[] to JArrayRef (#3569)
65797caa7 [sim] Fix halsim_ds_socket stringop overflow warning from GCC 10 (#3568)
66abb3988 [hal] Update runtime enum to allow selecting roborio 2 (#3565)
95a12e0ee [hal] UidSetter: Don't revert euid if its already current value (#3566)
27951442b [wpimath] Use external Eigen headers only (#3564)
c42e053ae [docs] Update to doxygen 1.9.2 (#3562)
e7048c8c8 [docs] Disable doxygen linking for common words that are also classes (#3563)
d8e0b6c97 [wpilibj] Fix java async interrupts (#3559)
5e6c34c61 Update to 2022 roborio image (#3537)
828f073eb [wpiutil] Fix uv::Buffer memory leaks caught by asan (#3555)
2dd5701ac [cscore] Fix mutex use-after-free in cscore test (#3557)
531439198 [ntcore] Fix NetworkTables memory leaks caught by asan (#3556)
3d9a4d585 [wpilibc] Fix AnalogTriggerOutput memory leak reported by asan (#3554)
54eda5928 [wpiutil] Ignore ubsan vptr upcast warning in SendableHelper moves (#3553)
5a4f75c9f [wpilib] Replace Speed controller comments with motor controller (NFC) (#3551)
7810f665f [wpiutil] Fix bug in uleb128 (#3540)
697e2dd33 [wpilib] Fix errant jaguar reference in comments (NFC) (#3550)
936c64ff5 [docs] Enable -linksource for javadocs (#3549)
1ea654954 [build] Upgrade CMake build to googletest 1.11.0 (#3548)
32d9949e4 [wpimath] Move controller tests to wpimath (#3541)
01ba56a8a [hal] Replace strncpy with memcpy (#3539)
e109c4251 [build] Rename makeSim flag to forceGazebo to better describe what it does (#3535)
e4c709164 [docs] Use a doxygen theme and add logo (#3533)
960b6e589 [wpimath] Fix Javadoc warning (#3532)
82eef8d5e [hal] Remove over current fault HAL functions from REV PDH (#3526)
aa3848b2c [wpimath] Move RobotDriveBase::ApplyDeadband() to MathUtil (#3529)
3b5d0d141 [wpimath] Add LinearFilter::BackwardFiniteDifference() (#3528)
c8fc715fe [wpimath] Upgrade drake files to v0.33.0 (#3531)
e5fe3a8e1 [build] Treat javadoc warnings as errors in CI and fix warnings (#3530)
e0c6cd3dc [wpimath] Add an operator for composing two Transform2ds (#3527)
2edd510ab [sim] Add sim wrappers for sensors that use SimDevice (#3517)
2b3e2ebc1 [hal] Fix HAL Notifier thread priority setting (#3522)
ab4cb5932 [gitignore] Update gitignore to ignore bazel / clion files (#3524)
57c8615af [build] Generate spotless patch on failure (#3523)
b90317321 Replace std::cout and std::cerr with fmt::print() (#3519)
10cc8b89c [hal] [wpilib] Add initial support for the REV PDH (#3503)
5d9ae3cdb [hal] Set HAL Notifier thread as RT by default (#3482)
192d251ee [wpilibcIntegrationTests] Properly disable DMA integration tests (#3514)
031962608 [wpilib] Add PS4Controller, remove Hand from GenericHID/XboxController (#3345)
25f6f478a [wpilib] Rename DriverStation::IsOperatorControl() to IsTeleop() (#3505)
e80f09f84 [wpilibj] Add unit tests (#3501)
c159f91f0 [wpilib] Only read DS control word once in IterativeRobotBase (#3504)
eb790a74d Add rio development docs documenting myRobot deploy tasks (#3508)
e47451f5a [wpimath] Replace auto with Eigen types (#3511)
252b8c83b Remove Java formatting from build task in CI (#3507)
09666ff29 Shorten Gazebo CI build (#3506)
baf2e501d Update myRobot to use 2021 java (#3509)
5ac60f0a2 [wpilib] Remove IterativeRobotBase mode init prints (#3500)
fb2ee8ec3 [wpilib] Add TimedRobot functions for running code on mode exit (#3499)
94e0db796 [wpilibc] Add more unit tests (#3494)
b25324695 [wpilibj] Add units to parameter names (NFC) (#3497)
1ac73a247 [hal] Rename PowerDistributionPanel to PowerDistribution (#3466)
2014115bc [examples] frisbeebot: Fix typo and reflow comments (NFC) (#3498)
4a944dc39 [examples] Consistently use 0 for controller port (#3496)
3838cc4ec Use unicode characters in docs equations (#3487)
85748f2e6 [examples] Add C++ TankDrive example (#3493)
d7b8aa56d [wpilibj] Rename DriverStation In[Mode] functions to follow style guide (#3488)
16e096cf8 [build] Fix CMake Windows CI (#3490)
50af74c38 [wpimath] Clean up NumericalIntegration and add Discretization tests (#3489)
bfc209b12 Automate fmt update (#3486)
e7f9331e4 [build] Update to Doxygen 1.9.1 (#3008)
ab8e8aa2a [wpimath] Update drake with upstream (#3484)
1ef826d1d [wpimath] Fix IOException path in WPIMath JNI (#3485)
52bddaa97 [wpimath] Disable iostream support for units and enable fmtlib (#3481)
e4dc3908b [wpiutil] Upgrade to fmtlib 8.0.1 (#3483)
1daadb812 [wpimath] Implement Dormand-Prince integration method (#3476)
9c2723391 [cscore] Add [[nodiscard]] to GrabFrame functions (#3479)
7a8796414 [wpilib] Add Notifier integration tests (#3480)
f8f13c536 [wpilibcExamples] Prefix decimal numbers with 0 (#3478)
1adb69c0f [ntcore] Use "NetworkTables" instead of "Network Tables" in NT specs (#3477)
5f5830b96 Upload wpiformat diff if one exists (#3474)
9fb4f35bb [wpimath] Add tests for DARE overload with Q, R, and N matrices (#3472)
c002e6f92 Run wpiformat (#3473)
c154e5262 [wpilib] Make solenoids exclusive use, PCM act like old sendable compressor (#3464)
6ddef1cca [hal] JNI setDIO: use a boolean and not a short (#3469)
9d68d9582 Remove extra newlines after open curly braces (NFC) (#3471)
a4233e1a1 [wpimath] Add script for updating Drake (#3470)
39373c6d2 Update README.md for new GCC version requirement (#3467)
d29acc90a [wpigui] Add option to reset UI on exit (#3463)
a371235b0 [ntcore] Fix dangling pointer in logger (#3465)
53b4891a5 [wpilibcintegrationtests] Fix deprecated Preferences usage (#3461)
646ded912 [wpimath] Remove incorrect discretization in pose estimators (#3460)
ea0b8f48e Fix some deprecation warnings due to fmtlib upgrade (#3459)
2067d7e30 [wpilibjexamples] Add wpimathjni, wpiutiljni to library path (#3455)
866571ab4 [wpiutil] Upgrade to fmtlib 8.0.0 (#3457)
4e1fa0308 [build] Skip PDB copy on windows build servers (#3458)
b45572167 [build] Change CI back to 18.04 docker images (#3456)
57a160f1b [wpilibc] Fix LiveWindow deprecation warning in RobotBase skeleton template (#3454)
29ae8640d [HLT] Implement duty cycle cross connect tests (#3453)
ee6377e54 [HLT] Add relay and analog cross connects (#3452)
b0f1ae7ea [build] CMake: Build the HAL even if WITH_CSCORE=OFF (#3449)
7aae2b72d Replace std::to_string() with fmt::format() (#3451)
73fcbbd74 [HLT] Add relay digital cross connect tests (#3450)
e7bedde83 [HLT] Add PWM tests that use DMA as the back end (#3447)
7253edb1e [wpilibc] Timer: Fix deprecated warning (#3446)
efa28125c [wpilibc] Add message to RobotBase on how to read stacktrace (#3444)
9832fcfe1 [hal] Fix DIO direction getter (#3445)
49c71f9f2 [wpilibj] Clarify robot quit message (#3364)
791770cf6 [wpimath] Move controller from wpilibj to wpimath (#3439)
9ce9188ff [wpimath] Add ReportWarning to MathShared (#3441)
362066a9b [wpilib] Deprecate getInstance() in favor of static functions (#3440)
26ff9371d Initial commit of cross connect integration test project (#3434)
4a36f86c8 [hal] Add support for DMA to Java (#3158)
85144e47f [commands] Unbreak build (#3438)
b417d961e Split Sendable into NT and non-NT portions (#3432)
ef4ea84cb [commands] Change grouping decorator impl to flatten nested group structures (#3335)
b422665a3 [examples] Invert right side of drive subsystems (#3437)
186dadf14 [hal] Error if attempting to set DIO output on an input port (#3436)
04e64db94 Remove redundant C++ lambda parentheses (NFC) (#3433)
f60994ad2 [wpiutil] Rename Java package to edu.wpi.first.util (#3431)
cfa1ca96f [wpilibc] Make ShuffleboardValue non-copyable (#3430)
4d9ff7643 Fix documentation warnings generated by JavaDoc (NFC) (#3428)
9e1b7e046 [build] Fix clang-tidy and clang-format (#3429)
a77c6ff3a [build] Upgrade clang-format and clang-tidy (NFC) (#3422)
099fde97d [wpilib] Improve PDP comments (NFC) (#3427)
f8fc2463e [wpilibc, wpiutil] Clean up includes (NFC) (#3426)
e246b7884 [wpimath] Clean up member initialization in feedforward classes (#3425)
c1e128bd5 Disable frivolous PMD warnings and enable PMD in ntcore (#3419)
8284075ee Run "Lint and Format" CI job on push as well as pull request (#3412)
f7db09a12 [wpimath] Move C++ filters into filter folder to match Java (#3417)
f9c3d54bd [wpimath] Reset error covariance in pose estimator ResetPosition() (#3418)
0773f4033 [hal] Ensure HAL status variables are initialized to zero (#3421)
d068fb321 [build] Upgrade CI to use 20.04 docker images (#3420)
8d054c940 [wpiutil] Remove STLExtras.h
80f1d7921 [wpiutil] Split function_ref to a separate header
64f541325 Use wpi::span instead of wpi::ArrayRef across all libraries (#3414)
2abbbd9e7 [build] clang-tidy: Remove bugprone-exception-escape (#3415)
a5c471af7 [wpimath] Add LQR template specialization for 2x2 system
edd2f0232 [wpimath] Add DARE solver for Q, R, and N with LQR ctor overloads
b2c3b2dd8 Use std::string_view and fmtlib across all libraries (#3402)
4f1cecb8e [wpiutil] Remove Path.h (#3413)
b336eac34 [build] Publish halsim_ws_core to Maven
2a09f6fa4 [build] Also build sim modules as static libraries
0e702eb79 [hal] Add a unified PCM object (#3331)
dea841103 [wpimath] Add fmtlib formatter overloads for Eigen::Matrix and units (#3409)
82856cf81 [wpiutil] Improve wpi::circular_buffer iterators (#3410)
8aecda03e [wpilib] Fix a documentation typo (#3408)
5c817082a [wpilib] Remove InterruptableSensorBase and replace with interrupt classes (#2410)
15c521a7f [wpimath] Fix drivetrain system identification (#3406)
989de4a1b [build] Force all linker warnings to be fatal for rio builds (#3407)
d9eeb45b0 [wpilibc] Add units to Ultrasonic class API (#3403)
fe570e000 [wpiutil] Replace llvm filesystem with C++17 filesystem (#3401)
01dc0249d [wpimath] Move SlewRateLimiter from wpilib to wpimath (#3399)
93523d572 [wpilibc] Clean up integration tests (#3400)
4f7a4464d [wpiutil] Rewrite StringExtras for std::string_view (#3394)
e09293a15 [wpilibc] Transition C++ classes to units::second_t (#3396)
827b17a52 [build] Create run tasks for Glass and OutlineViewer (#3397)
a61037996 [wpiutil] Avoid MSVC warning on span include (#3393)
4e2c3051b [wpilibc] Use std::string_view instead of Twine (#3380)
50915cb7e [wpilibc] MotorSafety::GetDescription(): Return std::string (#3390)
f4e2d26d5 [wpilibc] Move NullDeleter from frc/Base.h to wpi/NullDeleter.h (#3387)
cb0051ae6 [wpilibc] SimDeviceSim: use fmtlib (#3389)
a238cec12 [wpiutil] Deprecate wpi::math constants in favor of wpi::numbers (#3383)
393bf23c0 [ntcore, cscore, wpiutil] Standardize template impl files on .inc extension (NFC) (#3124)
e7d9ba135 [sim] Disable flaky web server integration tests (#3388)
0a0003c11 [wpilibjExamples] Fix name of Java swerve drive pose estimator example (#3382)
7e1b27554 [wpilibc] Use default copies and moves when possible (#3381)
fb2a56e2d [wpilibc] Remove START_ROBOT_CLASS macro (#3384)
84218bfb4 [wpilibc] Remove frc namespace shim (#3385)
dd7824340 [wpilibc] Remove C++ compiler version static asserts (#3386)
484cf9c0e [wpimath] Suppress the -Wmaybe-uninitialized warning in Eigen (#3378)
a04d1b4f9 [wpilibc] DriverStation: Remove ReportError and ReportWarning
831c10bdf [wpilibc] Errors: Use fmtlib
87603e400 [wpiutil] Import fmtlib (#3375)
442621672 [wpiutil] Add ArrayRef/std::span/wpi::span implicit conversions
bc15b953b [wpiutil] Add std::span implementation
6d20b1204 [wpiutil] StringRef, Twine, raw_ostream: Add std::string_view support (#3373)
2385c2a43 [wpilibc] Remove Utility.h (#3376)
87384ea68 [wpilib] Fix PIDController continuous range error calculations (#3170)
04dae799a [wpimath] Add SimpleMotorFeedforward::Calculate(velocity, nextVelocity) overload (#3183)
0768c3903 [wpilib] DifferentialDrive: Remove right side inversion (#3340)
8dd8d4d2d [wpimath] Fix redundant nested math package introduced by #3316 (#3368)
49b06beed [examples] Add Field2d to RamseteController example (#3371)
4c562a445 [wpimath] Fix typo in comment of update_eigen.py (#3369)
fdbbf1188 [wpimath] Add script for updating Eigen
f1e64b349 [wpimath] Move Eigen unsupported folder into eigeninclude
224f3a05c [sim] Fix build error when building with GCC 11.1 (#3361)
ff56d6861 [wpilibj] Fix SpeedController deprecated warnings (#3360)
1873fbefb [examples] Fix Swerve and Mecanum examples (#3359)
80b479e50 [examples] Fix SwerveBot example to use unique encoder ports (#3358)
1f7c9adee [wpilibjExamples] Fix pose estimator examples (#3356)
9ebc3b058 [outlineviewer] Change default size to 600x400 (#3353)
e21b443a4 [build] Gradle: Make C++ examples runnable (#3348)
da590120c [wpilibj] Add MotorController.setVoltage default (#3347)
561d53885 [build] Update opencv to 4.5.2, imgui/implot to latest (#3344)
44ad67ca8 [wpilibj] Preferences: Add missing Deprecated annotation (#3343)
3fe8fc75a [wpilibc] Revert "Return reference from GetInstance" (#3342)
3cc2da332 Merge branch '2022'
a3cd90dd7 [wpimath] Fix classpath used by generate_numbers.py (#3339)
d6cfdd3ba [wpilib] Preferences: Deprecate Put* in favor of Set* (#3337)
ba08baabb [wpimath] Update Drake DARE solver to v0.29.0 (#3336)
497b712f6 [wpilib] Make IterativeRobotBase::m_period private with getter
f00dfed7a [wpilib] Remove IterativeRobot base class
3c0846168 [hal] Use last error reporting instead of PARAMETER_OUT_OF_RANGE (#3328)
5ef2b4fdc [wpilibj] Fix @deprecated warning for SerialPort constructor (#3329)
23d2326d1 [hal] Report previous allocation location for indexed resource duplicates (#3322)
e338f9f19 [build] Fix wpilibc runCpp task (#3327)
c8ff626fe [wpimath] Move Java classes to edu.wpi.first.math (#3316)
4e424d51f [wpilibj] DifferentialDrivetrainSim: Rename constants to match the style guide (#3312)
6b50323b0 [cscore] Use Lock2DSize if possible for Windows USB cameras (#3326)
65c148536 [wpilibc] Fix "control reaches end of non-void function" warning (#3324)
f99f62bee [wpiutil] uv Handle: Use malloc/free instead of new/delete (#3325)
365f5449c [wpimath] Fix MecanumDriveKinematics (#3266)
ff52f207c [glass, wpilib] Rewrite Mechanism2d (#3281)
ee0eed143 [wpimath] Add DCMotor factory function for Romi motors (#3319)
512738072 [hal] Add HAL_GetLastError to enable better error messages from HAL calls (#3320)
ced654880 [glass, outlineviewer] Update Mac icons to macOS 11 style (#3313)
936d3b9f8 [templates] Add Java template for educational robot (#3309)
6e31230ad [examples] Fix odometry update in SwerveControllerCommand example (#3310)
05ebe9318 Merge branch 'main' into 2022
aaf24e255 [wpilib] Fix initial heading behavior in HolonomicDriveController (#3290)
8d961dfd2 [wpilibc] Remove ErrorBase (#3306)
659b37ef9 [wpiutil] StackTrace: Include offset on Linux (#3305)
0abf6c904 [wpilib] Move motor controllers to motorcontrol package (#3302)
4630191fa [wpiutil] circular_buffer: Use value initialization instead of passing zero (#3303)
b7b178f49 [wpilib] Remove Potentiometer interface
687066af3 [wpilib] Remove GyroBase
6b168ab0c [wpilib] Remove PIDController, PIDOutput, PIDSource
948625de9 [wpimath] Document conversion from filter cutoff frequency to time constant (#3299)
3848eb8b1 [wpilibc] Fix flywhel -> flywheel typo in FlywheelSim (#3298)
3abe0b9d4 [cscore] Move java package to edu.wpi.first.cscore (#3294)
d7fabe81f [wpilib] Remove RobotDrive (#3295)
1dc81669c [wpilib] Remove GearTooth (#3293)
01d0e1260 [wpilib] Revert move of RomiGyro into main wpilibc/j (#3296)
397e569aa [ntcore] Remove "using wpi" from nt namespace
79267f9e6 [ntcore] Remove NetworkTable -> nt::NetworkTable shim
48ebe5736 [ntcore] Remove deprecated Java interfaces and classes
c2064c78b [ntcore] Remove deprecated ITable interfaces
36608a283 [ntcore] Remove deprecated C++ APIs
a1c87e1e1 [glass] LogView: Add "copy to clipboard" button (#3274)
fa7240a50 [wpimath] Fix typo in quintic spline basis matrix
ffb4d38e2 [wpimath] Add derivation for spline basis matrices
f57c188f2 [wpilib] Add AnalogEncoder(int) ctor (#3273)
8471c4fb2 [wpilib] FieldObject2d: Add setTrajectory() method (#3277)
c97acd18e [glass] Field2d enhancements (#3234)
ffb590bfc [wpilib] Fix Compressor sendable properties (#3269)
6137f98eb [hal] Rename SimValueCallback2 to SimValueCallback (#3212)
a6f653969 [hal] Move registerSimPeriodic functions to HAL package (#3211)
10c038d9b [glass] Plot: Fix window creation after removal (#3264)
2d2eaa3ef [wpigui] Ensure window will be initially visible (#3256)
4d28b1f0c [wpimath] Use JNI for trajectory serialization (#3257)
3de800a60 [wpimath] TrajectoryUtil.h: Comment formatting (NFC) (#3262)
eff592377 [glass] Plot: Don't overwrite series ID (#3260)
a79faace1 [wpilibc] Return reference from GetInstance (#3247)
9550777b9 [wpilib] PWMSpeedController: Use PWM by composition (#3248)
c8521a3c3 [glass] Plot: Set reasonable default window size (#3261)
d71eb2cf3 [glass] Plot: Show full source name as tooltip and in popup (#3255)
160fb740f [hal] Use std::lround() instead of adding 0.5 and truncating (#3012)
48e9f3951 [wpilibj] Remove wpilibj package CameraServer (#3213)
8afa596fd [wpilib] Remove deprecated Sendable functions and SendableBase (#3210)
d3e45c297 [wpimath] Make C++ geometry classes immutable (#3249)
2c98939c1 [glass] StringChooser: Don't call SameLine() at end
a18a7409f [glass] NTStringChooser: Clear value of deleted entries
2f19cf452 [glass] NetworkTablesHelper: listen to delete events
da96707dc Merge branch 'main' into 2022
c3a8bdc24 [build] Fix clang-tidy action (#3246)
21624ef27 Add ImGui OutlineViewer (#3220)
1032c9b91 [wpiutil] Unbreak wpi::Format on Windows (#3242)
2e07902d7 [glass] NTField2D: Fix name lookup (#3233)
6e23e1840 [wpilibc] Remove WPILib.h (#3235)
3e22e4506 [wpilib] Make KoP drivetrain simulation weight 60 lbs (#3228)
79d1bd6c8 [glass] NetworkTablesSetting: Allow disable of server option (#3227)
fe341a16f [examples] Use more logical elevator setpoints in GearsBot (#3198)
62abf46b3 [glass] NetworkTablesSettings: Don't block GUI (#3226)
a95a5e0d9 [glass] Move NetworkTablesSettings to libglassnt (#3224)
d6f6ceaba [build] Run Spotless formatter (NFC) (#3221)
0922f8af5 [commands] CommandScheduler.requiring(): Note return can be null (NFC) (#2934)
6812302ff [examples] Make DriveDistanceOffboard example work in sim (#3199)
f3f86b8e7 [wpimath] Add pose estimator overload for vision + std dev measurement (#3200)
1a2680b9e [wpilibj] Change CommandBase.withName() to return CommandBase (#3209)
435bbb6a8 [command] RamseteCommand: Output 0 if interrupted (#3216)
3cf44e0a5 [hal] Add function for changing HAL Notifier thread priority (#3218)
40b367513 [wpimath] Units.java: Add kg-lb conversions (#3203)
9f563d584 [glass] NT: Fix return value in StringToDoubleArray (#3208)
af4adf537 [glass] Auto-size plots to fit window (#3193)
2560146da [sim] GUI: Add option to show prefix in Other Devices (#3186)
eae3a6397 gitignore: Ignore .cache directory (#3196)
959611420 [wpilib] Require non-zero positive value for PIDController.period (#3175)
9522f2e8c [wpimath] Add methods to concatenate trajectories (#3139)
e42a0b6cf [wpimath] Rotation2d comment formatting (NFC) (#3162)
d1c7032de [wpimath] Fix order of setting gyro offset in pose estimators (#3176)
d241bc81a [sim] Add DoubleSolenoidSim and SolenoidSim classes (#3177)
cb7f39afa [wpilibc] Add RobotController::GetBatteryVoltage() to C++ (#3179)
99b5ad9eb [wpilibj] Fix warnings that are not unused variables or deprecation (#3161)
c14b23775 [build] Fixup doxygen generated include dirs to match what users would need (#3154)
d447c7dc3 [sim] Add SimDeviceSim ctor overloads (#3134)
247420c9c [build] Remove jcenter repo (#3157)
04b112e00 [build] Include debug info in plugin published artifacts (#3149)
be0ce9900 [examples] Use PWMSparkMax instead of PWMVictorSPX (#3156)
69e8d0b65 [wpilib] Move RomiGyro into main wpilibc/j (#3143)
94e685e1b [wpimath] Add custom residual support to EKF (#3148)
5899f3dd2 [sim] GUI: Make keyboard settings loading more robust (#3167)
f82aa1d56 [wpilib] Fix HolonomicDriveController atReference() behavior (#3163)
fe5c2cf4b [wpimath] Remove ControllerUtil.java (#3169)
43d40c6e9 [wpiutil] Suppress unchecked cast in CombinedRuntimeLoader (#3155)
3d44d8f79 [wpimath] Fix argument order in UKF docs (NFC) (#3147)
ba6fe8ff2 [cscore] Add USB camera change event (#3123)
533725888 [build] Tweak OpenCV cmake search paths to work better on Linux (#3144)
29bf9d6ef [cscore] Add polled support to listener
483beb636 [ntcore] Move CallbackManager to wpiutil
fdaec7759 [examples] Instantiate m_ramseteController in example (#3142)
8494a5761 Rename default branch to main (#3140)
45590eea2 [wpigui] Hardcode window scale to 1 on macOS (#3135)
834a64920 [build] Publish libglass and libglassnt to Maven (#3127)
2c2ccb361 [wpimath] Fix Rotation2d equality operator (#3128)
fb5c8c39a [wpigui] clang-tidy: readability-braces-around-statements
f7d39193a [wpigui] Fix copyright in pfd and wpigui_metal.mm
aec796b21 [ntcore] Fix conditional jump on uninitialized value (#3125)
fb13bb239 [sim] GUI: Add right click popup for keyboard joystick settings (#3119)
c517ec677 [build] Update thirdparty-imgui to 1.79-2 (#3118)
e8cbf2a71 [wpimath] Fix typo in SwerveDrivePoseEstimator doc (NFC) (#3112)
e9c86df46 [wpimath] Add tests for swerve module optimization (#3100)
6ba8c289c [examples] Remove negative of ArcadeDrive(fwd, ..) in the C++ Getting Started Example (#3102)
3f1672e89 [hal] Add SimDevice createInt() and createLong() (#3110)
15be5cbf1 [examples] Fix segfault in GearsBot C++ example (#3111)
4cf0e5e6d Add quick links to API documentation in README (#3082)
6b1898f12 Fix RT priority docs (NFC) (#3098)
b3426e9c0 [wpimath] Fix missing whitespace in pose estimator doc (#3097)
38c1a1f3e [examples] Fix feildRelative -> fieldRelative typo in XControllerCommand examples (#3104)
4488e25f1 [glass] Shorten SmartDashboard window names (#3096)
cfdb3058e [wpilibj] Update SimDeviceSimTest (#3095)
64adff5fe [examples] Fix typo in ArcadeDrive constructor parameter name (#3092)
6efc58e3d [build] Fix issues with build on windows, deprecations, and native utils (#3090)
f393989a5 [wpimath, wpiutil] Add wpi::array for compile time size checking (#3087)
d6ed20c1e [build] Set macOS deployment target to 10.14 (#3088)
7c524014c [hal] Add [[nodiscard]] to HAL_WaitForNotifierAlarm() (#3085)
406d055f0 [wpilib] Fixup wouldHitLowerLimit in elevator and arm simulation classes. (#3076)
04a90b5dd [examples] Don't continually set setpoint in PotentiometerPID Examples (#3084)
8c5bfa013 [sim] GUI: Add max value setting for keyboard joysticks (#3083)
bc80c5535 [hal] Add SimValue reset() function (#3064)
9c3b51ca0 [wpilib] Document simulation APIs (#3079)
26584ff14 [wpimath] Add model description to LinearSystemId Javadocs (#3080)
42c3d5286 [examples] Sync Java and C++ trajectories in sim example (#3081)
64e72f710 [wpilibc] Add missing function RoboRioSim::ResetData (#3073)
e95503798 [wpimath] Add optimize() to SwerveModuleState (#3065)
fb99910c2 [hal] Add SimInt and SimLong wrappers for int/long SimValue (#3066)
e620bd4d3 [doc] Add machine-readable websocket specification (#3059)
a44e761d9 [glass] Add support for plot Y axis labels
ea1974d57 [wpigui] Update imgui and implot to latest
85a0bd43c [wpimath] Add RKF45 integration (#3047)
278e0f126 [glass] Use .controllable to set widgets' read-only state (#3035)
d8652cfd4 [wpimath] Make Java DCMotor API consistent with C++ and fix motor calcs (#3046)
377b7065a [build] Add toggleOffOn to Java spotless (#3053)
1e9c79c58 [sim] Use plant output to retrieve simulated position (#3043)
78147aa34 [sim] GUI: Fix Keyboard Joystick (#3052)
cd4a2265b [ntcore] Fix NetworkTableEntry::GetRaw() (#3051)
767ac1de1 [build] Use deploy key for doc publish (#3048)
d762215d1 [build] Add publish documentation script (#3040)
1fd09593c [examples] Add missing TestInit method to GettingStarted Example (#3039)
e45a0f6ce [examples] Add RomiGyro to the Romi Reference example (#3037)
94f852572 Update imaging link and fix typo (#3038)
d73cf64e5 [examples] Update RomiReference to match motor directions (#3036)
f945462ba Bump copyright year to 2021 (#3033)
b05946175 [wpimath] Catch Drake JNI exceptions and rethrow them (#3032)
62f0f8190 [wpimath] Deduplicate angle modulus functions (#2998)
bf8c0da4b [glass] Add "About" popup with version number (#3031)
dfdd6b389 [build] Increase Gradle heap size in Gazebo build (#3028)
f5e0fc3e9 Finish clang-tidy cleanups (#3003)
d741101fe [sim] Revert accidental commit of WSProvider_PDP.h (#3027)
e1620799c [examples] Add C++ RomiReference example (#2969)
749c7adb1 [command] Fix use-after-free in CommandScheduler (#3024)
921a73391 [sim] Add WS providers for AddressableLED, PCM, and Solenoid (#3026)
26d0004fe [build] Split Actions into different yml files (#3025)
948af6d5b [wpilib] PWMSpeedController.get(): Apply Inversion (#3016)
670a187a3 [wpilibc] SuppliedValueWidget.h: Forward declare ShuffleboardContainer (#3021)
be9f72502 [ntcore] NetworkTableValue: Use std::forward instead of std::move (#3022)
daf3f4cb1 [cscore] cscore_raw_cv.h: Fix error in PutFrame() (#3019)
5acda4cc7 [wpimath] ElevatorFeedforward.h: Add time.h include
8452af606 [wpimath] units/radiation.h: Add mass.h include
630d44952 [hal] ErrorsInternal.h: Add stdint.h include
7372cf7d9 [cscore] Windows NetworkUtil.cpp: Add missing include
b7e46c558 Include .h from .inc/.inl files (NFC) (#3017)
bf8f8710e [examples] Update Romi template and example (#2996)
6ffe5b775 [glass] Ensure NetworkTableTree parent context menu has an id (#3015)
be0805b85 [build] Update to WPILibVersioningPlugin 4.1.0 (#3014)
65b2359b2 [build] Add spotless for other files (#3007)
8651aa73e [examples] Enable NT Flush in Field2d examples (#3013)
78b542737 [build] Add Gazebo build to Actions CI (#3004)
fccf86532 [sim] DriverStationGui: Fix two bugs (#3010)
185741760 [sim] WSProvider_Joystick: Fix off-by-1 in incoming buttons (#3011)
ee7114a58 [glass] Add drive class widgets (#2975)
00fa91d0d [glass] Use ImGui style for gyro widget colors (#3009)
b7a25bfc3 ThirdPartyNotices: Add portable file dialogs license (#3005)
a2e46b9a1 [glass] modernize-use-nullptr (NFC) (#3006)
a751fa22d [build] Apply spotless for java formatting (#1768)
e563a0b7d [wpimath] Make LinearSystemLoop move-constructible and move-assignable (#2967)
49085ca94 [glass] Add context menus to remove and add NetworkTables values (#2979)
560a850a2 [glass] Add NetworkTables Log window (#2997)
66782e231 [sim] Create Left/Right drivetrain current accessors (#3001)
b60eb1544 clang-tidy: bugprone-virtual-near-miss
cbe59fa3b clang-tidy: google-explicit-constructor
c97c6dc06 clang-tidy: google-readability-casting (NFC)
32fa97d68 clang-tidy: modernize-use-nullptr (NFC)
aee460326 clang-tidy: modernize-pass-by-value
29c7da5f1 clang-tidy: modernize-make-unique
6131f4e32 clang-tidy: modernize-concat-nested-namespaces (NFC)
67e03e625 clang-tidy: modernize-use-equals-default
b124f9101 clang-tidy: modernize-use-default-member-init
d11a3a638 clang-tidy: modernize-use-override (NFC)
4cc0706b0 clang-tidy: modernize-use-using (NFC)
885f5a978 [wpilibc] Speed up ScopedTracerTest (#2999)
60b596457 [wpilibj] Fix typos (NFC) (#3000)
6e1919414 [build] Bring naming checkstyle rules up to date with Google Style guide (#1781)
8c8ec5e63 [wpilibj] Suppress unchecked cast warnings (#2995)
b8413ddd5 [wpiutil] Add noexcept to timestamp static functions (#2994)
5d976b6e1 [glass] Load NetworkTableView settings on first draw (#2993)
2b4317452 Replace NOLINT(runtime/explicit) comments with NOLINT (NFC) (#2992)
1c3011ba4 [glass] Fix handling of "/" NetworkTables key (#2991)
574a42f3b [hal] Fix UnsafeManipulateDIO status check (#2987)
9005cd59e [wpilib] Clamp input voltage in sim classes (#2955)
dd494d4ab [glass] NetworkTablesModel::Update(): Avoid use-after-move (#2988)
7cca469a1 [wpimath] NormalizeAngle: Make inline, remove unnamed namespace (#2986)
2aed432b4 Add braces to C++ single-line loops and conditionals (NFC) (#2973)
0291a3ff5 [wpiutil] StringRef: Add noexcept to several constructors (#2984)
5d7315280 [wpimath] Update UnitsTest.cpp copyright (#2985)
254931b9a [wpimath] Remove LinearSystem from LinearSystemLoop (#2968)
aa89744c9 Update OtherVersions.md to include wpimath info (#2983)
1cda3f5ad [glass] Fix styleguide (#2976)
8f1f64ffb Remove year from file copyright message (NFC) (#2972)
2bc0a7795 [examples] Fix wpiformat warning about utility include (#2971)
4204da6ad [glass] Add application icon
7ac39b10f [wpigui] Add icon support
6b567e006 [wpimath] Add support for varying vision standard deviations in pose estimators (#2956)
df299d6ed [wpimath] Add UnscentedKalmanFilter::Correct() overload (#2966)
4e34f0523 [examples] Use ADXRS450_GyroSim class in simulation example (#2964)
9962f6fd7 [wpilib] Give Field2d a default Sendable name (#2953)
f9d492f4b [sim] GUI: Show "Other Devices" window by default (#2961)
a8bb2ef1c [sim] Fix ADXRS450_GyroSim and DutyCycleEncoderSim (#2963)
240c629cd [sim] Try to guess "Map Gamepad" setting (#2960)
952567dd3 [wpilibc] Add missing move constructors and assignment operators (#2959)
10b396b4c [sim] Various WebSockets fixes and enhancements (#2952)
699bbe21a [examples] Fix comments in Gearsbot to match implementation (NFC) (#2957)
27b67deca [glass] Add more widgets (#2947)
581b7ec55 [wpilib] Add option to flush NetworkTables every iterative loop
acfbb1a44 [ntcore] DispatcherBase::Flush: Use wpi::Now()
d85a6d8fe [ntcore] Reduce limit on flush and update rate to 5 ms
20fbb5c63 [sim] Fix stringop truncation warning from GCC 10 (#2945)
1051a06a7 [glass] Show NT timestamps in seconds (#2944)
98dfc2620 [glass] Fix plots (#2943)
1ba0a2ced [sim] GUI: Add keyboard virtual joystick support (#2940)
4afb13f98 [examples] Replace M_PI with wpi::math::pi (#2938)
b27d33675 [examples] Enhance Romi templates (#2931)
00b9ae77f [sim] Change default WS port number to 3300 (#2932)
65219f309 [examples] Update Field2d position in periodic() (#2928)
f78d1d434 [sim] Process WS Encoder reset internally (#2927)
941edca59 [hal] Add Java SimDeviceDataJNI.getSimDeviceName (#2924)
a699435ed [wpilibj] Fix FlywheelSim argument order in constructor (#2922)
66d641718 [examples] Add tasks to run Java examples (#2920)
558e37c41 [examples] Add simple differential drive simulation example (#2918)
4f40d991e [glass] Switch name of Glass back to glass (#2919)
549af9900 [build] Update native-utils to 2021.0.6 (#2914)
b33693009 [glass] Change basename of glass to Glass (#2915)
c9a0edfb8 [glass] Package macOS application bundle
2c5668af4 [wpigui] Add platform-specific preferences save
751dea32a [wpilibc] Try to work around ABI break introduced in #2901 (#2917)
cd8f4bfb1 [build] Package up msvc runtime into maven artifact (#2913)
a6cfcc686 [wpilibc] Move SendableChooser Doxygen comments to header (NFC) (#2911)
b8c4f603d [wpimath] Upgrade to Eigen 3.3.9 (#2910)
0075e4b39 [wpilibj] Fix NPE in Field2d (#2909)
125af556c [simulation] Fix halsim_gui ntcore and wpiutil deps (#2908)
963ad5c25 [wpilib] Add noise to Differential Drive simulator (#2903)
387f56cb7 [examples] Add Romi reference Java example and templates (#2905)
b3deda38c [examples] Zero motors on disabledInit() in sim physics examples (#2906)
2a5ca7745 [glass] Add glass: an application for display of robot data
727940d84 [wpilib] Move Field2d to SmartDashboard
8cd42478e [wpilib] SendableBuilder: Make GetTable() visible
c11d34b26 [command] Use addCommands in command group templates (#2900)
339d7445b [sim] Add HAL hooks for simulationPeriodic (#2881)
d16f05f2c [wpilib] Fix SmartDashboard update order (#2896)
5427b32a4 [wpiutil] unique_function: Restrict implicit conversion (#2899)
f73701239 [ntcore] Add missing SetDefault initializer_list functions (#2898)
f5a6fc070 [sim] Add initialized flag for all solenoids on a PCM (#2897)
bdf5ba91a [wpilibj] Fix typo in ElevatorSim (#2895)
bc8f33877 [wpilib] Add pose estimators (#2867)
3413bfc06 [wpilib] PIDController: Recompute the error in AtSetpoint() (#2822)
2056f0ce0 [wpilib] Fix bugs in Hatchbot examples (#2893)
5eb8cfd69 [wpilibc] Fix MatchDataSender (#2892)
e6a425448 [build] Delete test folders after tests execute (#2891)
d478ad00d [imgui] Allow usage of imgui_stdlib (#2889)
53eda861d [build] Add unit-testing infrastructure to examples (#2863)
cc1d86ba6 [sim] Add title to simulator GUI window (#2888)
f0528f00e [build] CMake: Use project-specific binary and source dirs (#2886)
5cd2ad124 [wpilibc] Add Color::operator!= (#2887)
6c00e7a90 [build] CI CMake: build with GUI enabled (#2884)
53170bbb5 Update roboRIO toolchain installation instructions (#2883)
467258e05 [sim] GUI: Add option to not zero disconnected joysticks (#2876)
129be23c9 Clarify JDK installation instructions in readme (#2882)
8e9290e86 [build] Add separate CMake setting for wpimath (#2885)
7cf5bebf8 [wpilibj] Cache NT writes from DriverStation (#2780)
f7f9087fb [command] Fix timing issue in RamseteCommand (#2871)
256e7904f [wpilibj] SimDeviceSim: Fix sim value changed callback (#2880)
c8ea1b6c3 [wpilib] Add function to adjust LQR controller gain for pure time delay (#2878)
2816b06c0 [sim] HAL_GetControlWord: Fully zero output (#2873)
4c695ea08 Add toolchain installation instructions to README (#2875)
a14d51806 [wpimath] DCMotor: fix doc typo (NFC) (#2868)
017097791 [build] CMake: build sim extensions as shared libs (#2866)
f61726b5a [build] Fix cmake-config files (#2865)
fc27fdac5 [wpilibc] Cache NT values from driver station (#2768)
47c59859e [sim] Make SimDevice callbacks synchronous (#2861)
6e76ab9c0 [build] Turn on WITH_GUI for Windows cmake CI
5f78b7670 [build] Set GLFW_INSTALL to OFF
5e0808c84 [wpigui] Fix Windows cmake build
508f05a47 [imgui] Fix typo in Windows CMake target sources

Change-Id: I1737b45965f31803a96676bedc7dc40e337aa321
git-subtree-dir: third_party/allwpilib
git-subtree-split: e473a00f9785f9949e5ced30901baeaf426d2fc9
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/hal/src/main/native/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/athena/CTREPDP.h b/hal/src/main/native/athena/CTREPDP.h
new file mode 100644
index 0000000..dd4b298
--- /dev/null
+++ b/hal/src/main/native/athena/CTREPDP.h
@@ -0,0 +1,136 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you 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_pdp PDP Functions
+ * @ingroup hal_capi
+ * Functions to control the Power Distribution Panel.
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initializes a Power Distribution Panel.
+ *
+ * @param  module the module number to initialize
+ * @return the created PDP
+ */
+HAL_PDPHandle HAL_InitializePDP(int32_t module, const char* allocationLocation,
+                                int32_t* status);
+
+/**
+ * Cleans a PDP module.
+ *
+ * @param handle the module handle
+ */
+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
+ */
+HAL_Bool HAL_CheckPDPChannel(int32_t channel);
+
+/**
+ * Checks if a PDP module is valid.
+ *
+ * @param channel the module to check
+ * @return true if the module is valid, otherwise false
+ */
+HAL_Bool HAL_CheckPDPModule(int32_t module);
+
+/**
+ * Gets the temperature of the PDP.
+ *
+ * @param handle the module handle
+ * @return the module temperature (celsius)
+ */
+double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Gets the PDP input voltage.
+ *
+ * @param handle the module handle
+ * @return the input voltage (volts)
+ */
+double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Gets the current of a specific PDP channel.
+ *
+ * @param module  the module
+ * @param channel the channel
+ * @return the channel current (amps)
+ */
+double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
+                                int32_t* status);
+
+/**
+ * Gets the current of all 16 channels on the PDP.
+ *
+ * The array must be large enough to hold all channels.
+ *
+ * @param handle the module handle
+ * @param current the currents (output)
+ */
+void HAL_GetPDPAllChannelCurrents(HAL_PDPHandle handle, double* currents,
+                                  int32_t* status);
+
+/**
+ * Gets the total current of the PDP.
+ *
+ * @param handle the module handle
+ * @return the total current (amps)
+ */
+double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Gets the total power of the PDP.
+ *
+ * @param handle the module handle
+ * @return the total power (watts)
+ */
+double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Gets the total energy of the PDP.
+ *
+ * @param handle the module handle
+ * @return the total energy (joules)
+ */
+double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Resets the PDP accumulated energy.
+ *
+ * @param handle the module handle
+ */
+void HAL_ResetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status);
+
+/**
+ * Clears any PDP sticky faults.
+ *
+ * @param handle the module handle
+ */
+void HAL_ClearPDPStickyFaults(HAL_PDPHandle handle, int32_t* status);
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+/** @} */
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