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/cameraserver/src/dev/java/edu/wpi/first/cameraserver/DevMain.java b/cameraserver/src/dev/java/edu/wpi/first/cameraserver/DevMain.java
index 1182ac4..df4affa 100644
--- a/cameraserver/src/dev/java/edu/wpi/first/cameraserver/DevMain.java
+++ b/cameraserver/src/dev/java/edu/wpi/first/cameraserver/DevMain.java
@@ -1,17 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.cameraserver;
 
 public final class DevMain {
-  public static void main(String[] args) {
+  public static void main(String[] args) {}
 
-  }
-
-  private DevMain() {
-  }
+  private DevMain() {}
 }
diff --git a/cameraserver/src/dev/native/cpp/main.cpp b/cameraserver/src/dev/native/cpp/main.cpp
index e324b44..a3e363e 100644
--- a/cameraserver/src/dev/native/cpp/main.cpp
+++ b/cameraserver/src/dev/native/cpp/main.cpp
@@ -1,8 +1,5 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 int main() {}
diff --git a/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServer.java b/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServer.java
index 787b944..11de969 100644
--- a/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServer.java
+++ b/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServer.java
@@ -1,12 +1,27 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2020 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.cameraserver;
 
+import edu.wpi.first.cscore.AxisCamera;
+import edu.wpi.first.cscore.CameraServerJNI;
+import edu.wpi.first.cscore.CvSink;
+import edu.wpi.first.cscore.CvSource;
+import edu.wpi.first.cscore.MjpegServer;
+import edu.wpi.first.cscore.UsbCamera;
+import edu.wpi.first.cscore.VideoEvent;
+import edu.wpi.first.cscore.VideoException;
+import edu.wpi.first.cscore.VideoListener;
+import edu.wpi.first.cscore.VideoMode;
+import edu.wpi.first.cscore.VideoMode.PixelFormat;
+import edu.wpi.first.cscore.VideoProperty;
+import edu.wpi.first.cscore.VideoSink;
+import edu.wpi.first.cscore.VideoSource;
+import edu.wpi.first.networktables.EntryListenerFlags;
+import edu.wpi.first.networktables.NetworkTable;
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.networktables.NetworkTableInstance;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -14,45 +29,28 @@
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import edu.wpi.cscore.AxisCamera;
-import edu.wpi.cscore.CameraServerJNI;
-import edu.wpi.cscore.CvSink;
-import edu.wpi.cscore.CvSource;
-import edu.wpi.cscore.MjpegServer;
-import edu.wpi.cscore.UsbCamera;
-import edu.wpi.cscore.VideoEvent;
-import edu.wpi.cscore.VideoException;
-import edu.wpi.cscore.VideoListener;
-import edu.wpi.cscore.VideoMode;
-import edu.wpi.cscore.VideoMode.PixelFormat;
-import edu.wpi.cscore.VideoProperty;
-import edu.wpi.cscore.VideoSink;
-import edu.wpi.cscore.VideoSource;
-import edu.wpi.first.networktables.EntryListenerFlags;
-import edu.wpi.first.networktables.NetworkTable;
-import edu.wpi.first.networktables.NetworkTableEntry;
-import edu.wpi.first.networktables.NetworkTableInstance;
-
 /**
- * Singleton class for creating and keeping camera servers.
- * Also publishes camera information to NetworkTables.
+ * Singleton class for creating and keeping camera servers. Also publishes camera information to
+ * NetworkTables.
  */
+@SuppressWarnings("PMD.UnusedPrivateField")
 public final class CameraServer {
   public static final int kBasePort = 1181;
 
-  @Deprecated
-  public static final int kSize640x480 = 0;
-  @Deprecated
-  public static final int kSize320x240 = 1;
-  @Deprecated
-  public static final int kSize160x120 = 2;
+  @Deprecated public static final int kSize640x480 = 0;
+  @Deprecated public static final int kSize320x240 = 1;
+  @Deprecated public static final int kSize160x120 = 2;
 
   private static final String kPublishName = "/CameraPublisher";
   private static CameraServer server;
 
   /**
    * Get the CameraServer instance.
+   *
+   * @return The CameraServer instance.
+   * @deprecated Use the static methods
    */
+  @Deprecated
   public static synchronized CameraServer getInstance() {
     if (server == null) {
       server = new CameraServer();
@@ -60,32 +58,226 @@
     return server;
   }
 
-  private final AtomicInteger m_defaultUsbDevice;
-  private String m_primarySourceName;
-  private final Map<String, VideoSource> m_sources;
-  private final Map<String, VideoSink> m_sinks;
-  private final Map<Integer, NetworkTable> m_tables;  // indexed by source handle
+  private static final AtomicInteger m_defaultUsbDevice = new AtomicInteger();
+  private static String m_primarySourceName;
+  private static final Map<String, VideoSource> m_sources = new HashMap<>();
+  private static final Map<String, VideoSink> m_sinks = new HashMap<>();
+  private static final Map<Integer, NetworkTable> m_tables =
+      new HashMap<>(); // indexed by source handle
   // source handle indexed by sink handle
-  private final Map<Integer, Integer> m_fixedSources;
-  private final NetworkTable m_publishTable;
-  private final VideoListener m_videoListener; //NOPMD
-  private final int m_tableListener; //NOPMD
-  private int m_nextPort;
-  private String[] m_addresses;
+  private static final Map<Integer, Integer> m_fixedSources = new HashMap<>();
+  private static final NetworkTable m_publishTable =
+      NetworkTableInstance.getDefault().getTable(kPublishName);
 
-  @SuppressWarnings("JavadocMethod")
+  // We publish sources to NetworkTables using the following structure:
+  // "/CameraPublisher/{Source.Name}/" - root
+  // - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
+  // - "streams" (string array): URLs that can be used to stream data
+  // - "description" (string): Description of the source
+  // - "connected" (boolean): Whether source is connected
+  // - "mode" (string): Current video mode
+  // - "modes" (string array): Available video modes
+  // - "Property/{Property}" - Property values
+  // - "PropertyInfo/{Property}" - Property supporting information
+
+  // Listener for video events
+  private static final VideoListener m_videoListener =
+      new VideoListener(
+          event -> {
+            switch (event.kind) {
+              case kSourceCreated:
+                {
+                  // Create subtable for the camera
+                  NetworkTable table = m_publishTable.getSubTable(event.name);
+                  m_tables.put(event.sourceHandle, table);
+                  table.getEntry("source").setString(makeSourceValue(event.sourceHandle));
+                  table
+                      .getEntry("description")
+                      .setString(CameraServerJNI.getSourceDescription(event.sourceHandle));
+                  table
+                      .getEntry("connected")
+                      .setBoolean(CameraServerJNI.isSourceConnected(event.sourceHandle));
+                  table
+                      .getEntry("streams")
+                      .setStringArray(getSourceStreamValues(event.sourceHandle));
+                  try {
+                    VideoMode mode = CameraServerJNI.getSourceVideoMode(event.sourceHandle);
+                    table.getEntry("mode").setDefaultString(videoModeToString(mode));
+                    table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
+                  } catch (VideoException ignored) {
+                    // Do nothing. Let the other event handlers update this if there is an error.
+                  }
+                  break;
+                }
+              case kSourceDestroyed:
+                {
+                  NetworkTable table = m_tables.get(event.sourceHandle);
+                  if (table != null) {
+                    table.getEntry("source").setString("");
+                    table.getEntry("streams").setStringArray(new String[0]);
+                    table.getEntry("modes").setStringArray(new String[0]);
+                  }
+                  break;
+                }
+              case kSourceConnected:
+                {
+                  NetworkTable table = m_tables.get(event.sourceHandle);
+                  if (table != null) {
+                    // update the description too (as it may have changed)
+                    table
+                        .getEntry("description")
+                        .setString(CameraServerJNI.getSourceDescription(event.sourceHandle));
+                    table.getEntry("connected").setBoolean(true);
+                  }
+                  break;
+                }
+              case kSourceDisconnected:
+                {
+                  NetworkTable table = m_tables.get(event.sourceHandle);
+                  if (table != null) {
+                    table.getEntry("connected").setBoolean(false);
+                  }
+                  break;
+                }
+              case kSourceVideoModesUpdated:
+                {
+                  NetworkTable table = m_tables.get(event.sourceHandle);
+                  if (table != null) {
+                    table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
+                  }
+                  break;
+                }
+              case kSourceVideoModeChanged:
+                {
+                  NetworkTable table = m_tables.get(event.sourceHandle);
+                  if (table != null) {
+                    table.getEntry("mode").setString(videoModeToString(event.mode));
+                  }
+                  break;
+                }
+              case kSourcePropertyCreated:
+                {
+                  NetworkTable table = m_tables.get(event.sourceHandle);
+                  if (table != null) {
+                    putSourcePropertyValue(table, event, true);
+                  }
+                  break;
+                }
+              case kSourcePropertyValueUpdated:
+                {
+                  NetworkTable table = m_tables.get(event.sourceHandle);
+                  if (table != null) {
+                    putSourcePropertyValue(table, event, false);
+                  }
+                  break;
+                }
+              case kSourcePropertyChoicesUpdated:
+                {
+                  NetworkTable table = m_tables.get(event.sourceHandle);
+                  if (table != null) {
+                    try {
+                      String[] choices =
+                          CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
+                      table
+                          .getEntry("PropertyInfo/" + event.name + "/choices")
+                          .setStringArray(choices);
+                    } catch (VideoException ignored) {
+                      // ignore
+                    }
+                  }
+                  break;
+                }
+              case kSinkSourceChanged:
+              case kSinkCreated:
+              case kSinkDestroyed:
+              case kNetworkInterfacesChanged:
+                {
+                  m_addresses = CameraServerJNI.getNetworkInterfaces();
+                  updateStreamValues();
+                  break;
+                }
+              default:
+                break;
+            }
+          },
+          0x4fff,
+          true);
+
+  private static final int m_tableListener =
+      NetworkTableInstance.getDefault()
+          .addEntryListener(
+              kPublishName + "/",
+              event -> {
+                String relativeKey = event.name.substring(kPublishName.length() + 1);
+
+                // get source (sourceName/...)
+                int subKeyIndex = relativeKey.indexOf('/');
+                if (subKeyIndex == -1) {
+                  return;
+                }
+                String sourceName = relativeKey.substring(0, subKeyIndex);
+                VideoSource source = m_sources.get(sourceName);
+                if (source == null) {
+                  return;
+                }
+
+                // get subkey
+                relativeKey = relativeKey.substring(subKeyIndex + 1);
+
+                // handle standard names
+                String propName;
+                if ("mode".equals(relativeKey)) {
+                  // reset to current mode
+                  event.getEntry().setString(videoModeToString(source.getVideoMode()));
+                  return;
+                } else if (relativeKey.startsWith("Property/")) {
+                  propName = relativeKey.substring(9);
+                } else if (relativeKey.startsWith("RawProperty/")) {
+                  propName = relativeKey.substring(12);
+                } else {
+                  return; // ignore
+                }
+
+                // everything else is a property
+                VideoProperty property = source.getProperty(propName);
+                switch (property.getKind()) {
+                  case kNone:
+                    return;
+                  case kBoolean:
+                    // reset to current setting
+                    event.getEntry().setBoolean(property.get() != 0);
+                    return;
+                  case kInteger:
+                  case kEnum:
+                    // reset to current setting
+                    event.getEntry().setDouble(property.get());
+                    return;
+                  case kString:
+                    // reset to current setting
+                    event.getEntry().setString(property.getString());
+                    return;
+                  default:
+                    return;
+                }
+              },
+              EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);
+  private static int m_nextPort = kBasePort;
+  private static String[] m_addresses = new String[0];
+
+  @SuppressWarnings("MissingJavadocMethod")
   private static String makeSourceValue(int source) {
     switch (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))) {
       case kUsb:
         return "usb:" + CameraServerJNI.getUsbCameraPath(source);
-      case kHttp: {
-        String[] urls = CameraServerJNI.getHttpCameraUrls(source);
-        if (urls.length > 0) {
-          return "ip:" + urls[0];
-        } else {
-          return "ip:";
+      case kHttp:
+        {
+          String[] urls = CameraServerJNI.getHttpCameraUrls(source);
+          if (urls.length > 0) {
+            return "ip:" + urls[0];
+          } else {
+            return "ip:";
+          }
         }
-      }
       case kCv:
         return "cv:";
       default:
@@ -93,13 +285,13 @@
     }
   }
 
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   private static String makeStreamValue(String address, int port) {
     return "mjpg:http://" + address + ":" + port + "/?action=stream";
   }
 
-  @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
-  private synchronized String[] getSinkStreamValues(int sink) {
+  @SuppressWarnings("MissingJavadocMethod")
+  private static synchronized String[] getSinkStreamValues(int sink) {
     // Ignore all but MjpegServer
     if (VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink)) != VideoSink.Kind.kMjpeg) {
       return new String[0];
@@ -119,7 +311,7 @@
       values.add(makeStreamValue(CameraServerJNI.getHostname() + ".local", port));
       for (String addr : m_addresses) {
         if ("127.0.0.1".equals(addr)) {
-          continue;  // ignore localhost
+          continue; // ignore localhost
         }
         values.add(makeStreamValue(addr, port));
       }
@@ -128,11 +320,11 @@
     return values.toArray(new String[0]);
   }
 
-  @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
-  private synchronized String[] getSourceStreamValues(int source) {
+  @SuppressWarnings("MissingJavadocMethod")
+  private static synchronized String[] getSourceStreamValues(int source) {
     // Ignore all but HttpCamera
     if (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))
-            != VideoSource.Kind.kHttp) {
+        != VideoSource.Kind.kHttp) {
       return new String[0];
     }
 
@@ -150,7 +342,7 @@
         int sinkSource = CameraServerJNI.getSinkSource(sink);
         if (source == sinkSource
             && VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink))
-            == VideoSink.Kind.kMjpeg) {
+                == VideoSink.Kind.kMjpeg) {
           // Add USB-only passthrough
           String[] finalValues = Arrays.copyOf(values, values.length + 1);
           int port = CameraServerJNI.getMjpegServerPort(sink);
@@ -163,15 +355,16 @@
     return values;
   }
 
-  @SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP", "PMD.CyclomaticComplexity"})
-  private synchronized void updateStreamValues() {
+  @SuppressWarnings("MissingJavadocMethod")
+  private static synchronized void updateStreamValues() {
     // Over all the sinks...
     for (VideoSink i : m_sinks.values()) {
       int sink = i.getHandle();
 
       // Get the source's subtable (if none exists, we're done)
-      int source = Objects.requireNonNullElseGet(m_fixedSources.get(sink),
-          () -> CameraServerJNI.getSinkSource(sink));
+      int source =
+          Objects.requireNonNullElseGet(
+              m_fixedSources.get(sink), () -> CameraServerJNI.getSinkSource(sink));
 
       if (source == 0) {
         continue;
@@ -208,7 +401,7 @@
     }
   }
 
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   private static String pixelFormatToString(PixelFormat pixelFormat) {
     switch (pixelFormat) {
       case kMJPEG:
@@ -228,13 +421,19 @@
 
   /// Provide string description of video mode.
   /// The returned string is "{width}x{height} {format} {fps} fps".
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   private static String videoModeToString(VideoMode mode) {
-    return mode.width + "x" + mode.height + " " + pixelFormatToString(mode.pixelFormat)
-        + " " + mode.fps + " fps";
+    return mode.width
+        + "x"
+        + mode.height
+        + " "
+        + pixelFormatToString(mode.pixelFormat)
+        + " "
+        + mode.fps
+        + " fps";
   }
 
-  @SuppressWarnings("JavadocMethod")
+  @SuppressWarnings("MissingJavadocMethod")
   private static String[] getSourceModeValues(int sourceHandle) {
     VideoMode[] modes = CameraServerJNI.enumerateSourceVideoModes(sourceHandle);
     String[] modeStrings = new String[modes.length];
@@ -244,7 +443,7 @@
     return modeStrings;
   }
 
-  @SuppressWarnings({"JavadocMethod", "PMD.CyclomaticComplexity"})
+  @SuppressWarnings("MissingJavadocMethod")
   private static void putSourcePropertyValue(NetworkTable table, VideoEvent event, boolean isNew) {
     String name;
     String infoName;
@@ -270,14 +469,18 @@
         case kEnum:
           if (isNew) {
             entry.setDefaultDouble(event.value);
-            table.getEntry(infoName + "/min").setDouble(
-                CameraServerJNI.getPropertyMin(event.propertyHandle));
-            table.getEntry(infoName + "/max").setDouble(
-                CameraServerJNI.getPropertyMax(event.propertyHandle));
-            table.getEntry(infoName + "/step").setDouble(
-                CameraServerJNI.getPropertyStep(event.propertyHandle));
-            table.getEntry(infoName + "/default").setDouble(
-                CameraServerJNI.getPropertyDefault(event.propertyHandle));
+            table
+                .getEntry(infoName + "/min")
+                .setDouble(CameraServerJNI.getPropertyMin(event.propertyHandle));
+            table
+                .getEntry(infoName + "/max")
+                .setDouble(CameraServerJNI.getPropertyMax(event.propertyHandle));
+            table
+                .getEntry(infoName + "/step")
+                .setDouble(CameraServerJNI.getPropertyStep(event.propertyHandle));
+            table
+                .getEntry(infoName + "/default")
+                .setDouble(CameraServerJNI.getPropertyDefault(event.propertyHandle));
           } else {
             entry.setDouble(event.value);
           }
@@ -297,203 +500,21 @@
     }
   }
 
-  @SuppressWarnings({"JavadocMethod", "PMD.UnusedLocalVariable", "PMD.ExcessiveMethodLength",
-      "PMD.NPathComplexity"})
-  private CameraServer() {
-    m_defaultUsbDevice = new AtomicInteger();
-    m_sources = new HashMap<>();
-    m_sinks = new HashMap<>();
-    m_fixedSources = new HashMap<>();
-    m_tables = new HashMap<>();
-    m_publishTable = NetworkTableInstance.getDefault().getTable(kPublishName);
-    m_nextPort = kBasePort;
-    m_addresses = new String[0];
-
-    // We publish sources to NetworkTables using the following structure:
-    // "/CameraPublisher/{Source.Name}/" - root
-    // - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
-    // - "streams" (string array): URLs that can be used to stream data
-    // - "description" (string): Description of the source
-    // - "connected" (boolean): Whether source is connected
-    // - "mode" (string): Current video mode
-    // - "modes" (string array): Available video modes
-    // - "Property/{Property}" - Property values
-    // - "PropertyInfo/{Property}" - Property supporting information
-
-    // Listener for video events
-    m_videoListener = new VideoListener(event -> {
-      switch (event.kind) {
-        case kSourceCreated: {
-          // Create subtable for the camera
-          NetworkTable table = m_publishTable.getSubTable(event.name);
-          m_tables.put(event.sourceHandle, table);
-          table.getEntry("source").setString(makeSourceValue(event.sourceHandle));
-          table.getEntry("description").setString(
-              CameraServerJNI.getSourceDescription(event.sourceHandle));
-          table.getEntry("connected").setBoolean(
-              CameraServerJNI.isSourceConnected(event.sourceHandle));
-          table.getEntry("streams").setStringArray(getSourceStreamValues(event.sourceHandle));
-          try {
-            VideoMode mode = CameraServerJNI.getSourceVideoMode(event.sourceHandle);
-            table.getEntry("mode").setDefaultString(videoModeToString(mode));
-            table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
-          } catch (VideoException ignored) {
-            // Do nothing. Let the other event handlers update this if there is an error.
-          }
-          break;
-        }
-        case kSourceDestroyed: {
-          NetworkTable table = m_tables.get(event.sourceHandle);
-          if (table != null) {
-            table.getEntry("source").setString("");
-            table.getEntry("streams").setStringArray(new String[0]);
-            table.getEntry("modes").setStringArray(new String[0]);
-          }
-          break;
-        }
-        case kSourceConnected: {
-          NetworkTable table = m_tables.get(event.sourceHandle);
-          if (table != null) {
-            // update the description too (as it may have changed)
-            table.getEntry("description").setString(
-                CameraServerJNI.getSourceDescription(event.sourceHandle));
-            table.getEntry("connected").setBoolean(true);
-          }
-          break;
-        }
-        case kSourceDisconnected: {
-          NetworkTable table = m_tables.get(event.sourceHandle);
-          if (table != null) {
-            table.getEntry("connected").setBoolean(false);
-          }
-          break;
-        }
-        case kSourceVideoModesUpdated: {
-          NetworkTable table = m_tables.get(event.sourceHandle);
-          if (table != null) {
-            table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
-          }
-          break;
-        }
-        case kSourceVideoModeChanged: {
-          NetworkTable table = m_tables.get(event.sourceHandle);
-          if (table != null) {
-            table.getEntry("mode").setString(videoModeToString(event.mode));
-          }
-          break;
-        }
-        case kSourcePropertyCreated: {
-          NetworkTable table = m_tables.get(event.sourceHandle);
-          if (table != null) {
-            putSourcePropertyValue(table, event, true);
-          }
-          break;
-        }
-        case kSourcePropertyValueUpdated: {
-          NetworkTable table = m_tables.get(event.sourceHandle);
-          if (table != null) {
-            putSourcePropertyValue(table, event, false);
-          }
-          break;
-        }
-        case kSourcePropertyChoicesUpdated: {
-          NetworkTable table = m_tables.get(event.sourceHandle);
-          if (table != null) {
-            try {
-              String[] choices = CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
-              table.getEntry("PropertyInfo/" + event.name + "/choices").setStringArray(choices);
-            } catch (VideoException ignored) {
-              // ignore
-            }
-          }
-          break;
-        }
-        case kSinkSourceChanged:
-        case kSinkCreated:
-        case kSinkDestroyed:
-        case kNetworkInterfacesChanged: {
-          m_addresses = CameraServerJNI.getNetworkInterfaces();
-          updateStreamValues();
-          break;
-        }
-        default:
-          break;
-      }
-    }, 0x4fff, true);
-
-    // Listener for NetworkTable events
-    // We don't currently support changing settings via NT due to
-    // synchronization issues, so just update to current setting if someone
-    // else tries to change it.
-    m_tableListener = NetworkTableInstance.getDefault().addEntryListener(kPublishName + "/",
-      event -> {
-        String relativeKey = event.name.substring(kPublishName.length() + 1);
-
-        // get source (sourceName/...)
-        int subKeyIndex = relativeKey.indexOf('/');
-        if (subKeyIndex == -1) {
-          return;
-        }
-        String sourceName = relativeKey.substring(0, subKeyIndex);
-        VideoSource source = m_sources.get(sourceName);
-        if (source == null) {
-          return;
-        }
-
-        // get subkey
-        relativeKey = relativeKey.substring(subKeyIndex + 1);
-
-        // handle standard names
-        String propName;
-        if ("mode".equals(relativeKey)) {
-          // reset to current mode
-          event.getEntry().setString(videoModeToString(source.getVideoMode()));
-          return;
-        } else if (relativeKey.startsWith("Property/")) {
-          propName = relativeKey.substring(9);
-        } else if (relativeKey.startsWith("RawProperty/")) {
-          propName = relativeKey.substring(12);
-        } else {
-          return;  // ignore
-        }
-
-        // everything else is a property
-        VideoProperty property = source.getProperty(propName);
-        switch (property.getKind()) {
-          case kNone:
-            return;
-          case kBoolean:
-            // reset to current setting
-            event.getEntry().setBoolean(property.get() != 0);
-            return;
-          case kInteger:
-          case kEnum:
-            // reset to current setting
-            event.getEntry().setDouble(property.get());
-            return;
-          case kString:
-            // reset to current setting
-            event.getEntry().setString(property.getString());
-            return;
-          default:
-            return;
-        }
-      }, EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);
-  }
+  private CameraServer() {}
 
   /**
    * Start automatically capturing images to send to the dashboard.
    *
-   * <p>You should call this method to see a camera feed on the dashboard.
-   * If you also want to perform vision processing on the roboRIO, use
-   * getVideo() to get access to the camera images.
+   * <p>You should call this method to see a camera feed on the dashboard. If you also want to
+   * perform vision processing on the roboRIO, use getVideo() to get access to the camera images.
    *
-   * <p>The first time this overload is called, it calls
-   * {@link #startAutomaticCapture(int)} with device 0, creating a camera
-   * named "USB Camera 0".  Subsequent calls increment the device number
+   * <p>The first time this overload is called, it calls {@link #startAutomaticCapture(int)} with
+   * device 0, creating a camera named "USB Camera 0". Subsequent calls increment the device number
    * (e.g. 1, 2, etc).
+   *
+   * @return The USB camera capturing images.
    */
-  public UsbCamera startAutomaticCapture() {
+  public static UsbCamera startAutomaticCapture() {
     UsbCamera camera = startAutomaticCapture(m_defaultUsbDevice.getAndIncrement());
     CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
     return camera;
@@ -502,12 +523,13 @@
   /**
    * Start automatically capturing images to send to the dashboard.
    *
-   * <p>This overload calls {@link #startAutomaticCapture(String, int)} with
-   * a name of "USB Camera {dev}".
+   * <p>This overload calls {@link #startAutomaticCapture(String, int)} with a name of "USB Camera
+   * {dev}".
    *
    * @param dev The device number of the camera interface
+   * @return The USB camera capturing images.
    */
-  public UsbCamera startAutomaticCapture(int dev) {
+  public static UsbCamera startAutomaticCapture(int dev) {
     UsbCamera camera = new UsbCamera("USB Camera " + dev, dev);
     startAutomaticCapture(camera);
     CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
@@ -519,8 +541,9 @@
    *
    * @param name The name to give the camera
    * @param dev The device number of the camera interface
+   * @return The USB camera capturing images.
    */
-  public UsbCamera startAutomaticCapture(String name, int dev) {
+  public static UsbCamera startAutomaticCapture(String name, int dev) {
     UsbCamera camera = new UsbCamera(name, dev);
     startAutomaticCapture(camera);
     CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
@@ -532,8 +555,9 @@
    *
    * @param name The name to give the camera
    * @param path The device path (e.g. "/dev/video0") of the camera
+   * @return The USB camera capturing images.
    */
-  public UsbCamera startAutomaticCapture(String name, String path) {
+  public static UsbCamera startAutomaticCapture(String name, String path) {
     UsbCamera camera = new UsbCamera(name, path);
     startAutomaticCapture(camera);
     CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
@@ -541,12 +565,12 @@
   }
 
   /**
-   * Start automatically capturing images to send to the dashboard from
-   * an existing camera.
+   * Start automatically capturing images to send to the dashboard from an existing camera.
    *
    * @param camera Camera
+   * @return The MJPEG server serving images from the given camera.
    */
-  public MjpegServer startAutomaticCapture(VideoSource camera) {
+  public static MjpegServer startAutomaticCapture(VideoSource camera) {
     addCamera(camera);
     MjpegServer server = addServer("serve_" + camera.getName());
     server.setSource(camera);
@@ -556,24 +580,24 @@
   /**
    * Adds an Axis IP camera.
    *
-   * <p>This overload calls {@link #addAxisCamera(String, String)} with
-   * name "Axis Camera".
+   * <p>This overload calls {@link #addAxisCamera(String, String)} with name "Axis Camera".
    *
    * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
+   * @return The Axis camera capturing images.
    */
-  public AxisCamera addAxisCamera(String host) {
+  public static AxisCamera addAxisCamera(String host) {
     return addAxisCamera("Axis Camera", host);
   }
 
   /**
    * Adds an Axis IP camera.
    *
-   * <p>This overload calls {@link #addAxisCamera(String, String[])} with
-   * name "Axis Camera".
+   * <p>This overload calls {@link #addAxisCamera(String, String[])} with name "Axis Camera".
    *
    * @param hosts Array of Camera host IPs/DNS names
+   * @return The Axis camera capturing images.
    */
-  public AxisCamera addAxisCamera(String[] hosts) {
+  public static AxisCamera addAxisCamera(String[] hosts) {
     return addAxisCamera("Axis Camera", hosts);
   }
 
@@ -582,8 +606,9 @@
    *
    * @param name The name to give the camera
    * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
+   * @return The Axis camera capturing images.
    */
-  public AxisCamera addAxisCamera(String name, String host) {
+  public static AxisCamera addAxisCamera(String name, String host) {
     AxisCamera camera = new AxisCamera(name, host);
     // Create a passthrough MJPEG server for USB access
     startAutomaticCapture(camera);
@@ -596,8 +621,9 @@
    *
    * @param name The name to give the camera
    * @param hosts Array of Camera host IPs/DNS names
+   * @return The Axis camera capturing images.
    */
-  public AxisCamera addAxisCamera(String name, String[] hosts) {
+  public static AxisCamera addAxisCamera(String name, String[] hosts) {
     AxisCamera camera = new AxisCamera(name, hosts);
     // Create a passthrough MJPEG server for USB access
     startAutomaticCapture(camera);
@@ -606,16 +632,18 @@
   }
 
   /**
-   * Adds a virtual camera for switching between two streams.  Unlike the
-   * other addCamera methods, this returns a VideoSink rather than a
-   * VideoSource.  Calling setSource() on the returned object can be used
-   * to switch the actual source of the stream.
+   * Adds a virtual camera for switching between two streams. Unlike the other addCamera methods,
+   * this returns a VideoSink rather than a VideoSource. Calling setSource() on the returned object
+   * can be used to switch the actual source of the stream.
+   *
+   * @param name The name to give the camera
+   * @return The MJPEG server serving images from the given camera.
    */
-  public MjpegServer addSwitchedCamera(String name) {
+  public static MjpegServer addSwitchedCamera(String name) {
     // create a dummy CvSource
     CvSource source = new CvSource(name, VideoMode.PixelFormat.kMJPEG, 160, 120, 30);
     MjpegServer server = startAutomaticCapture(source);
-    synchronized (this) {
+    synchronized (CameraServer.class) {
       m_fixedSources.put(server.getHandle(), source.getHandle());
     }
 
@@ -623,15 +651,17 @@
   }
 
   /**
-   * Get OpenCV access to the primary camera feed.  This allows you to
-   * get images from the camera for image processing on the roboRIO.
+   * Get OpenCV access to the primary camera feed. This allows you to get images from the camera for
+   * image processing on the roboRIO.
    *
-   * <p>This is only valid to call after a camera feed has been added
-   * with startAutomaticCapture() or addServer().
+   * <p>This is only valid to call after a camera feed has been added with startAutomaticCapture()
+   * or addServer().
+   *
+   * @return OpenCV sink for the primary camera feed
    */
-  public CvSink getVideo() {
+  public static CvSink getVideo() {
     VideoSource source;
-    synchronized (this) {
+    synchronized (CameraServer.class) {
       if (m_primarySourceName == null) {
         throw new VideoException("no camera available");
       }
@@ -644,15 +674,16 @@
   }
 
   /**
-   * Get OpenCV access to the specified camera.  This allows you to get
-   * images from the camera for image processing on the roboRIO.
+   * Get OpenCV access to the specified camera. This allows you to get images from the camera for
+   * image processing on the roboRIO.
    *
    * @param camera Camera (e.g. as returned by startAutomaticCapture).
+   * @return OpenCV sink for the specified camera
    */
-  public CvSink getVideo(VideoSource camera) {
+  public static CvSink getVideo(VideoSource camera) {
     String name = "opencv_" + camera.getName();
 
-    synchronized (this) {
+    synchronized (CameraServer.class) {
       VideoSink sink = m_sinks.get(name);
       if (sink != null) {
         VideoSink.Kind kind = sink.getKind();
@@ -670,14 +701,15 @@
   }
 
   /**
-   * Get OpenCV access to the specified camera.  This allows you to get
-   * images from the camera for image processing on the roboRIO.
+   * Get OpenCV access to the specified camera. This allows you to get images from the camera for
+   * image processing on the roboRIO.
    *
    * @param name Camera name
+   * @return OpenCV sink for the specified camera
    */
-  public CvSink getVideo(String name) {
+  public static CvSink getVideo(String name) {
     VideoSource source;
-    synchronized (this) {
+    synchronized (CameraServer.class) {
       source = m_sources.get(name);
       if (source == null) {
         throw new VideoException("could not find camera " + name);
@@ -687,14 +719,15 @@
   }
 
   /**
-   * Create a MJPEG stream with OpenCV input. This can be called to pass custom
-   * annotated images to the dashboard.
+   * Create a MJPEG stream with OpenCV input. This can be called to pass custom annotated images to
+   * the dashboard.
    *
    * @param name Name to give the stream
    * @param width Width of the image being sent
    * @param height Height of the image being sent
+   * @return OpenCV source for the MJPEG stream
    */
-  public CvSource putVideo(String name, int width, int height) {
+  public static CvSource putVideo(String name, int width, int height) {
     CvSource source = new CvSource(name, VideoMode.PixelFormat.kMJPEG, width, height, 30);
     startAutomaticCapture(source);
     return source;
@@ -704,10 +737,11 @@
    * Adds a MJPEG server at the next available port.
    *
    * @param name Server name
+   * @return The MJPEG server
    */
-  public MjpegServer addServer(String name) {
+  public static MjpegServer addServer(String name) {
     int port;
-    synchronized (this) {
+    synchronized (CameraServer.class) {
       port = m_nextPort;
       m_nextPort++;
     }
@@ -718,8 +752,10 @@
    * Adds a MJPEG server.
    *
    * @param name Server name
+   * @param port Server port
+   * @return The MJPEG server
    */
-  public MjpegServer addServer(String name, int port) {
+  public static MjpegServer addServer(String name, int port) {
     MjpegServer server = new MjpegServer(name, port);
     addServer(server);
     return server;
@@ -730,8 +766,8 @@
    *
    * @param server Server
    */
-  public void addServer(VideoSink server) {
-    synchronized (this) {
+  public static void addServer(VideoSink server) {
+    synchronized (CameraServer.class) {
       m_sinks.put(server.getName(), server);
     }
   }
@@ -741,8 +777,8 @@
    *
    * @param name Server name
    */
-  public void removeServer(String name) {
-    synchronized (this) {
+  public static void removeServer(String name) {
+    synchronized (CameraServer.class) {
       m_sinks.remove(name);
     }
   }
@@ -750,11 +786,13 @@
   /**
    * Get server for the primary camera feed.
    *
-   * <p>This is only valid to call after a camera feed has been added
-   * with startAutomaticCapture() or addServer().
+   * <p>This is only valid to call after a camera feed has been added with startAutomaticCapture()
+   * or addServer().
+   *
+   * @return The server for the primary camera feed
    */
-  public VideoSink getServer() {
-    synchronized (this) {
+  public static VideoSink getServer() {
+    synchronized (CameraServer.class) {
       if (m_primarySourceName == null) {
         throw new VideoException("no camera available");
       }
@@ -766,9 +804,10 @@
    * Gets a server by name.
    *
    * @param name Server name
+   * @return The server
    */
-  public VideoSink getServer(String name) {
-    synchronized (this) {
+  public static VideoSink getServer(String name) {
+    synchronized (CameraServer.class) {
       return m_sinks.get(name);
     }
   }
@@ -778,9 +817,9 @@
    *
    * @param camera Camera
    */
-  public void addCamera(VideoSource camera) {
+  public static void addCamera(VideoSource camera) {
     String name = camera.getName();
-    synchronized (this) {
+    synchronized (CameraServer.class) {
       if (m_primarySourceName == null) {
         m_primarySourceName = name;
       }
@@ -793,8 +832,8 @@
    *
    * @param name Camera name
    */
-  public void removeCamera(String name) {
-    synchronized (this) {
+  public static void removeCamera(String name) {
+    synchronized (CameraServer.class) {
       m_sources.remove(name);
     }
   }
diff --git a/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServerShared.java b/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServerShared.java
index c9cbb8f..4726de1 100644
--- a/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServerShared.java
+++ b/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServerShared.java
@@ -1,13 +1,9 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.cameraserver;
 
-
 public interface CameraServerShared {
   /**
    * get the main thread id func.
diff --git a/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServerSharedStore.java b/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServerSharedStore.java
index c0cf2bb..3d9e119 100644
--- a/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServerSharedStore.java
+++ b/cameraserver/src/main/java/edu/wpi/first/cameraserver/CameraServerSharedStore.java
@@ -1,56 +1,48 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.cameraserver;
 
 public final class CameraServerSharedStore {
   private static CameraServerShared cameraServerShared;
 
-  private CameraServerSharedStore() {
-  }
+  private CameraServerSharedStore() {}
 
   /**
-   * get the CameraServerShared object.
+   * Get the CameraServerShared object.
+   *
+   * @return The CameraServerSharedObject
    */
   public static synchronized CameraServerShared getCameraServerShared() {
     if (cameraServerShared == null) {
-      cameraServerShared = new CameraServerShared() {
+      cameraServerShared =
+          new CameraServerShared() {
+            @Override
+            public void reportVideoServer(int id) {}
 
-        @Override
-        public void reportVideoServer(int id) {
+            @Override
+            public void reportUsbCamera(int id) {}
 
-        }
+            @Override
+            public void reportDriverStationError(String error) {}
 
-        @Override
-        public void reportUsbCamera(int id) {
+            @Override
+            public void reportAxisCamera(int id) {}
 
-        }
-
-        @Override
-        public void reportDriverStationError(String error) {
-
-        }
-
-        @Override
-        public void reportAxisCamera(int id) {
-
-        }
-
-        @Override
-        public Long getRobotMainThreadId() {
-          return null;
-        }
-      };
+            @Override
+            public Long getRobotMainThreadId() {
+              return null;
+            }
+          };
     }
     return cameraServerShared;
   }
 
   /**
-   * set the CameraServerShared object.
+   * Set the CameraServerShared object.
+   *
+   * @param shared The CameraServerShared object.
    */
   public static synchronized void setCameraServerShared(CameraServerShared shared) {
     cameraServerShared = shared;
diff --git a/cameraserver/src/main/java/edu/wpi/first/vision/VisionPipeline.java b/cameraserver/src/main/java/edu/wpi/first/vision/VisionPipeline.java
index 6df10e7..29c285f 100644
--- a/cameraserver/src/main/java/edu/wpi/first/vision/VisionPipeline.java
+++ b/cameraserver/src/main/java/edu/wpi/first/vision/VisionPipeline.java
@@ -1,26 +1,24 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 package edu.wpi.first.vision;
 
 import org.opencv.core.Mat;
 
 /**
- * A vision pipeline is responsible for running a group of
- * OpenCV algorithms to extract data from an image.
+ * A vision pipeline is responsible for running a group of OpenCV algorithms to extract data from an
+ * image.
  *
  * @see VisionRunner
  * @see VisionThread
  */
 public interface VisionPipeline {
   /**
-   * Processes the image input and sets the result objects.
-   * Implementations should make these objects accessible.
+   * Processes the image input and sets the result objects. Implementations should make these
+   * objects accessible.
+   *
+   * @param image The image to process.
    */
   void process(Mat image);
-
 }
diff --git a/cameraserver/src/main/java/edu/wpi/first/vision/VisionRunner.java b/cameraserver/src/main/java/edu/wpi/first/vision/VisionRunner.java
index 8d8b12e..ab7072f 100644
--- a/cameraserver/src/main/java/edu/wpi/first/vision/VisionRunner.java
+++ b/cameraserver/src/main/java/edu/wpi/first/vision/VisionRunner.java
@@ -1,22 +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.
 
 package edu.wpi.first.vision;
 
+import edu.wpi.first.cameraserver.CameraServerSharedStore;
+import edu.wpi.first.cscore.CvSink;
+import edu.wpi.first.cscore.VideoSource;
 import org.opencv.core.Mat;
 
-import edu.wpi.cscore.CvSink;
-import edu.wpi.cscore.VideoSource;
-import edu.wpi.first.cameraserver.CameraServerSharedStore;
-
 /**
- * A vision runner is a convenient wrapper object to make it easy to run vision pipelines
- * from robot code. The easiest  way to use this is to run it in a {@link VisionThread}
- * and use the listener to take snapshots of the pipeline's outputs.
+ * A vision runner is a convenient wrapper object to make it easy to run vision pipelines from robot
+ * code. The easiest way to use this is to run it in a {@link VisionThread} and use the listener to
+ * take snapshots of the pipeline's outputs.
  *
  * @see VisionPipeline
  * @see VisionThread
@@ -45,17 +41,16 @@
      * @param pipeline the vision pipeline that ran
      */
     void copyPipelineOutputs(P pipeline);
-
   }
 
   /**
-   * Creates a new vision runner. It will take images from the {@code videoSource}, send them to
-   * the {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert
-   * user code when it is safe to access the pipeline's outputs.
+   * Creates a new vision runner. It will take images from the {@code videoSource}, send them to the
+   * {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert user
+   * code when it is safe to access the pipeline's outputs.
    *
    * @param videoSource the video source to use to supply images for the pipeline
-   * @param pipeline    the vision pipeline to run
-   * @param listener    a function to call after the pipeline has finished running
+   * @param pipeline the vision pipeline to run
+   * @param listener a function to call after the pipeline has finished running
    */
   public VisionRunner(VideoSource videoSource, P pipeline, Listener<? super P> listener) {
     this.m_pipeline = pipeline;
@@ -64,15 +59,15 @@
   }
 
   /**
-   * Runs the pipeline one time, giving it the next image from the video source specified
-   * in the constructor. This will block until the source either has an image or throws an error.
-   * If the source successfully supplied a frame, the pipeline's image input will be set,
-   * the pipeline will run, and the listener specified in the constructor will be called to notify
-   * it that the pipeline ran.
+   * Runs the pipeline one time, giving it the next image from the video source specified in the
+   * constructor. This will block until the source either has an image or throws an error. If the
+   * source successfully supplied a frame, the pipeline's image input will be set, the pipeline will
+   * run, and the listener specified in the constructor will be called to notify it that the
+   * pipeline ran.
    *
-   * <p>This method is exposed to allow teams to add additional functionality or have their own
-   * ways to run the pipeline. Most teams, however, should just use {@link #runForever} in its own
-   * thread using a {@link VisionThread}.</p>
+   * <p>This method is exposed to allow teams to add additional functionality or have their own ways
+   * to run the pipeline. Most teams, however, should just use {@link #runForever} in its own thread
+   * using a {@link VisionThread}.
    */
   public void runOnce() {
     Long id = CameraServerSharedStore.getCameraServerShared().getRobotMainThreadId();
@@ -98,11 +93,11 @@
   }
 
   /**
-   * A convenience method that calls {@link #runOnce()} in an infinite loop. This must
-   * be run in a dedicated thread, and cannot be used in the main robot thread because
-   * it will freeze the robot program.
+   * A convenience method that calls {@link #runOnce()} in an infinite loop. This must be run in a
+   * dedicated thread, and cannot be used in the main robot thread because it will freeze the robot
+   * program.
    *
-   * <p><strong>Do not call this method directly from the main thread.</strong></p>
+   * <p><strong>Do not call this method directly from the main thread.</strong>
    *
    * @throws IllegalStateException if this is called from the main robot thread
    * @see VisionThread
@@ -119,9 +114,7 @@
     }
   }
 
-  /**
-   * Stop a RunForever() loop.
-   */
+  /** Stop a RunForever() loop. */
   public void stop() {
     m_enabled = false;
   }
diff --git a/cameraserver/src/main/java/edu/wpi/first/vision/VisionThread.java b/cameraserver/src/main/java/edu/wpi/first/vision/VisionThread.java
index 576cb96..6f1a1e3 100644
--- a/cameraserver/src/main/java/edu/wpi/first/vision/VisionThread.java
+++ b/cameraserver/src/main/java/edu/wpi/first/vision/VisionThread.java
@@ -1,18 +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.
 
 package edu.wpi.first.vision;
 
-import edu.wpi.cscore.VideoSource;
+import edu.wpi.first.cscore.VideoSource;
 
 /**
- * A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread;
- * it does not prevent the program from exiting when all other non-daemon threads
- * have finished running.
+ * A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread; it
+ * does not prevent the program from exiting when all other non-daemon threads have finished
+ * running.
  *
  * @see VisionPipeline
  * @see VisionRunner
@@ -34,14 +31,12 @@
    * equivalent to {@code new VisionThread(new VisionRunner<>(videoSource, pipeline, listener))}.
    *
    * @param videoSource the source for images the pipeline should process
-   * @param pipeline    the pipeline to run
-   * @param listener    the listener to copy outputs from the pipeline after it runs
-   * @param <P>         the type of the pipeline
+   * @param pipeline the pipeline to run
+   * @param listener the listener to copy outputs from the pipeline after it runs
+   * @param <P> the type of the pipeline
    */
-  public <P extends VisionPipeline> VisionThread(VideoSource videoSource,
-                                                 P pipeline,
-                                                 VisionRunner.Listener<? super P> listener) {
+  public <P extends VisionPipeline> VisionThread(
+      VideoSource videoSource, P pipeline, VisionRunner.Listener<? super P> listener) {
     this(new VisionRunner<>(videoSource, pipeline, listener));
   }
-
 }
diff --git a/cameraserver/src/main/java/edu/wpi/first/vision/package-info.java b/cameraserver/src/main/java/edu/wpi/first/vision/package-info.java
index e2e5c62..3715570 100644
--- a/cameraserver/src/main/java/edu/wpi/first/vision/package-info.java
+++ b/cameraserver/src/main/java/edu/wpi/first/vision/package-info.java
@@ -1,22 +1,19 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 /**
- * Classes in the {@code edu.wpi.first.vision} package are designed to
- * simplify using OpenCV vision processing code from a robot program.
+ * Classes in the {@code edu.wpi.first.vision} package are designed to simplify using OpenCV vision
+ * processing code from a robot program.
  *
- * <p>An example use case for grabbing a yellow tote from 2015 in autonomous:
- * <br>
+ * <p>An example use case for grabbing a yellow tote from 2015 in autonomous: <br>
+ *
  * <pre><code>
  * public class Robot extends IterativeRobot
  *     implements VisionRunner.Listener&lt;MyFindTotePipeline&gt; {
  *
  *      // A USB camera connected to the roboRIO.
- *      private {@link edu.wpi.cscore.VideoSource VideoSource} usbCamera;
+ *      private {@link edu.wpi.first.cscore.VideoSource VideoSource} usbCamera;
  *
  *      // A vision pipeline. This could be handwritten or generated by GRIP.
  *      // This has to implement {@link edu.wpi.first.vision.VisionPipeline}.
@@ -47,7 +44,7 @@
  *
  *     {@literal @}Override
  *      public void robotInit() {
- *          usbCamera = CameraServer.getInstance().startAutomaticCapture(0);
+ *          usbCamera = CameraServer.startAutomaticCapture(0);
  *          findTotePipeline = new MyFindTotePipeline();
  *          findToteThread = new VisionThread(usbCamera, findTotePipeline, this);
  *      }
diff --git a/cameraserver/src/main/native/cpp/cameraserver/CameraServer.cpp b/cameraserver/src/main/native/cpp/cameraserver/CameraServer.cpp
index f7647de..1a4d42a 100644
--- a/cameraserver/src/main/native/cpp/cameraserver/CameraServer.cpp
+++ b/cameraserver/src/main/native/cpp/cameraserver/CameraServer.cpp
@@ -1,23 +1,20 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "cameraserver/CameraServer.h"
 
 #include <atomic>
 #include <vector>
 
+#include <fmt/format.h>
 #include <networktables/NetworkTable.h>
 #include <networktables/NetworkTableInstance.h>
 #include <wpi/DenseMap.h>
-#include <wpi/ManagedStatic.h>
 #include <wpi/SmallString.h>
+#include <wpi/StringExtras.h>
 #include <wpi/StringMap.h>
 #include <wpi/mutex.h>
-#include <wpi/raw_ostream.h>
 
 #include "cameraserver/CameraServerShared.h"
 #include "ntcore_cpp.h"
@@ -26,8 +23,9 @@
 
 static constexpr char const* kPublishName = "/CameraPublisher";
 
-struct CameraServer::Impl {
-  Impl();
+namespace {
+struct Instance {
+  Instance();
   std::shared_ptr<nt::NetworkTable> GetSourceTable(CS_Source source);
   std::vector<std::string> GetSinkStreamValues(CS_Sink sink);
   std::vector<std::string> GetSourceStreamValues(CS_Source source);
@@ -40,41 +38,45 @@
   wpi::StringMap<cs::VideoSink> m_sinks;
   wpi::DenseMap<CS_Sink, CS_Source> m_fixedSources;
   wpi::DenseMap<CS_Source, std::shared_ptr<nt::NetworkTable>> m_tables;
-  std::shared_ptr<nt::NetworkTable> m_publishTable;
+  std::shared_ptr<nt::NetworkTable> m_publishTable{
+      nt::NetworkTableInstance::GetDefault().GetTable(kPublishName)};
   cs::VideoListener m_videoListener;
   int m_tableListener;
-  int m_nextPort;
+  int m_nextPort{CameraServer::kBasePort};
   std::vector<std::string> m_addresses;
 };
+}  // namespace
 
-CameraServer* CameraServer::GetInstance() {
-  struct Creator {
-    static void* call() { return new CameraServer{}; }
-  };
-  struct Deleter {
-    static void call(void* ptr) { delete static_cast<CameraServer*>(ptr); }
-  };
-  static wpi::ManagedStatic<CameraServer, Creator, Deleter> instance;
-  return &(*instance);
+static Instance& GetInstance() {
+  static Instance instance;
+  return instance;
 }
 
-static wpi::StringRef MakeSourceValue(CS_Source source,
-                                      wpi::SmallVectorImpl<char>& buf) {
+CameraServer* CameraServer::GetInstance() {
+  ::GetInstance();
+  static CameraServer instance;
+  return &instance;
+}
+
+static std::string_view MakeSourceValue(CS_Source source,
+                                        wpi::SmallVectorImpl<char>& buf) {
   CS_Status status = 0;
   buf.clear();
   switch (cs::GetSourceKind(source, &status)) {
     case CS_SOURCE_USB: {
-      wpi::StringRef prefix{"usb:"};
+      std::string_view prefix{"usb:"};
       buf.append(prefix.begin(), prefix.end());
       auto path = cs::GetUsbCameraPath(source, &status);
       buf.append(path.begin(), path.end());
       break;
     }
     case CS_SOURCE_HTTP: {
-      wpi::StringRef prefix{"ip:"};
+      std::string_view prefix{"ip:"};
       buf.append(prefix.begin(), prefix.end());
       auto urls = cs::GetHttpCameraUrls(source, &status);
-      if (!urls.empty()) buf.append(urls[0].begin(), urls[0].end());
+      if (!urls.empty()) {
+        buf.append(urls[0].begin(), urls[0].end());
+      }
       break;
     }
     case CS_SOURCE_CV:
@@ -83,27 +85,25 @@
       return "unknown:";
   }
 
-  return wpi::StringRef{buf.begin(), buf.size()};
+  return {buf.begin(), buf.size()};
 }
 
-static std::string MakeStreamValue(const wpi::Twine& address, int port) {
-  return ("mjpg:http://" + address + wpi::Twine(':') + wpi::Twine(port) +
-          "/?action=stream")
-      .str();
+static std::string MakeStreamValue(std::string_view address, int port) {
+  return fmt::format("mjpg:http://{}:{}/?action=stream", address, port);
 }
 
-std::shared_ptr<nt::NetworkTable> CameraServer::Impl::GetSourceTable(
-    CS_Source source) {
+std::shared_ptr<nt::NetworkTable> Instance::GetSourceTable(CS_Source source) {
   std::scoped_lock lock(m_mutex);
   return m_tables.lookup(source);
 }
 
-std::vector<std::string> CameraServer::Impl::GetSinkStreamValues(CS_Sink sink) {
+std::vector<std::string> Instance::GetSinkStreamValues(CS_Sink sink) {
   CS_Status status = 0;
 
   // Ignore all but MjpegServer
-  if (cs::GetSinkKind(sink, &status) != CS_SINK_MJPEG)
-    return std::vector<std::string>{};
+  if (cs::GetSinkKind(sink, &status) != CS_SINK_MJPEG) {
+    return {};
+  }
 
   // Get port
   int port = cs::GetMjpegServerPort(sink, &status);
@@ -119,7 +119,9 @@
     values.emplace_back(MakeStreamValue(cs::GetHostname() + ".local", port));
 
     for (const auto& addr : m_addresses) {
-      if (addr == "127.0.0.1") continue;  // ignore localhost
+      if (addr == "127.0.0.1") {
+        continue;  // ignore localhost
+      }
       values.emplace_back(MakeStreamValue(addr, port));
     }
   }
@@ -127,17 +129,19 @@
   return values;
 }
 
-std::vector<std::string> CameraServer::Impl::GetSourceStreamValues(
-    CS_Source source) {
+std::vector<std::string> Instance::GetSourceStreamValues(CS_Source source) {
   CS_Status status = 0;
 
   // Ignore all but HttpCamera
-  if (cs::GetSourceKind(source, &status) != CS_SOURCE_HTTP)
-    return std::vector<std::string>{};
+  if (cs::GetSourceKind(source, &status) != CS_SOURCE_HTTP) {
+    return {};
+  }
 
   // Generate values
   auto values = cs::GetHttpCameraUrls(source, &status);
-  for (auto& value : values) value = "mjpg:" + value;
+  for (auto& value : values) {
+    value = "mjpg:" + value;
+  }
 
 #ifdef __FRC_ROBORIO__
   // Look to see if we have a passthrough server for this source
@@ -159,7 +163,7 @@
   return values;
 }
 
-void CameraServer::Impl::UpdateStreamValues() {
+void Instance::UpdateStreamValues() {
   std::scoped_lock lock(m_mutex);
   // Over all the sinks...
   for (const auto& i : m_sinks) {
@@ -168,16 +172,24 @@
 
     // Get the source's subtable (if none exists, we're done)
     CS_Source source = m_fixedSources.lookup(sink);
-    if (source == 0) source = cs::GetSinkSource(sink, &status);
-    if (source == 0) continue;
+    if (source == 0) {
+      source = cs::GetSinkSource(sink, &status);
+    }
+    if (source == 0) {
+      continue;
+    }
     auto table = m_tables.lookup(source);
     if (table) {
       // Don't set stream values if this is a HttpCamera passthrough
-      if (cs::GetSourceKind(source, &status) == CS_SOURCE_HTTP) continue;
+      if (cs::GetSourceKind(source, &status) == CS_SOURCE_HTTP) {
+        continue;
+      }
 
       // Set table value
       auto values = GetSinkStreamValues(sink);
-      if (!values.empty()) table->GetEntry("streams").SetStringArray(values);
+      if (!values.empty()) {
+        table->GetEntry("streams").SetStringArray(values);
+      }
     }
   }
 
@@ -190,7 +202,9 @@
     if (table) {
       // Set table value
       auto values = GetSourceStreamValues(source);
-      if (!values.empty()) table->GetEntry("streams").SetStringArray(values);
+      if (!values.empty()) {
+        table->GetEntry("streams").SetStringArray(values);
+      }
     }
   }
 }
@@ -213,79 +227,72 @@
 }
 
 static std::string VideoModeToString(const cs::VideoMode& mode) {
-  std::string rv;
-  wpi::raw_string_ostream oss{rv};
-  oss << mode.width << "x" << mode.height;
-  oss << " " << PixelFormatToString(mode.pixelFormat) << " ";
-  oss << mode.fps << " fps";
-  return oss.str();
+  return fmt::format("{}x{} {} {} fps", mode.width, mode.height,
+                     PixelFormatToString(mode.pixelFormat), mode.fps);
 }
 
 static std::vector<std::string> GetSourceModeValues(int source) {
   std::vector<std::string> rv;
   CS_Status status = 0;
-  for (const auto& mode : cs::EnumerateSourceVideoModes(source, &status))
+  for (const auto& mode : cs::EnumerateSourceVideoModes(source, &status)) {
     rv.emplace_back(VideoModeToString(mode));
+  }
   return rv;
 }
 
 static void PutSourcePropertyValue(nt::NetworkTable* table,
                                    const cs::VideoEvent& event, bool isNew) {
-  wpi::SmallString<64> name;
-  wpi::SmallString<64> infoName;
-  if (wpi::StringRef{event.name}.startswith("raw_")) {
-    name = "RawProperty/";
-    name += event.name;
-    infoName = "RawPropertyInfo/";
-    infoName += event.name;
+  std::string_view namePrefix;
+  std::string_view infoPrefix;
+  if (wpi::starts_with(event.name, "raw_")) {
+    namePrefix = "RawProperty";
+    infoPrefix = "RawPropertyInfo";
   } else {
-    name = "Property/";
-    name += event.name;
-    infoName = "PropertyInfo/";
-    infoName += event.name;
+    namePrefix = "Property";
+    infoPrefix = "PropertyInfo";
   }
 
   wpi::SmallString<64> buf;
   CS_Status status = 0;
-  nt::NetworkTableEntry entry = table->GetEntry(name);
+  nt::NetworkTableEntry entry =
+      table->GetEntry(fmt::format("{}/{}", namePrefix, event.name));
   switch (event.propertyKind) {
     case CS_PROP_BOOLEAN:
-      if (isNew)
+      if (isNew) {
         entry.SetDefaultBoolean(event.value != 0);
-      else
+      } else {
         entry.SetBoolean(event.value != 0);
+      }
       break;
     case CS_PROP_INTEGER:
     case CS_PROP_ENUM:
       if (isNew) {
         entry.SetDefaultDouble(event.value);
-        table->GetEntry(infoName + "/min")
+        table->GetEntry(fmt::format("{}/{}/min", infoPrefix, event.name))
             .SetDouble(cs::GetPropertyMin(event.propertyHandle, &status));
-        table->GetEntry(infoName + "/max")
+        table->GetEntry(fmt::format("{}/{}/max", infoPrefix, event.name))
             .SetDouble(cs::GetPropertyMax(event.propertyHandle, &status));
-        table->GetEntry(infoName + "/step")
+        table->GetEntry(fmt::format("{}/{}/step", infoPrefix, event.name))
             .SetDouble(cs::GetPropertyStep(event.propertyHandle, &status));
-        table->GetEntry(infoName + "/default")
+        table->GetEntry(fmt::format("{}/{}/default", infoPrefix, event.name))
             .SetDouble(cs::GetPropertyDefault(event.propertyHandle, &status));
       } else {
         entry.SetDouble(event.value);
       }
       break;
     case CS_PROP_STRING:
-      if (isNew)
+      if (isNew) {
         entry.SetDefaultString(event.valueStr);
-      else
+      } else {
         entry.SetString(event.valueStr);
+      }
       break;
     default:
       break;
   }
 }
 
-CameraServer::Impl::Impl()
-    : m_publishTable{nt::NetworkTableInstance::GetDefault().GetTable(
-          kPublishName)},
-      m_nextPort(kBasePort) {
+Instance::Instance() {
   // We publish sources to NetworkTables using the following structure:
   // "/CameraPublisher/{Source.Name}/" - root
   // - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
@@ -351,41 +358,48 @@
           }
           case cs::VideoEvent::kSourceDisconnected: {
             auto table = GetSourceTable(event.sourceHandle);
-            if (table) table->GetEntry("connected").SetBoolean(false);
+            if (table) {
+              table->GetEntry("connected").SetBoolean(false);
+            }
             break;
           }
           case cs::VideoEvent::kSourceVideoModesUpdated: {
             auto table = GetSourceTable(event.sourceHandle);
-            if (table)
+            if (table) {
               table->GetEntry("modes").SetStringArray(
                   GetSourceModeValues(event.sourceHandle));
+            }
             break;
           }
           case cs::VideoEvent::kSourceVideoModeChanged: {
             auto table = GetSourceTable(event.sourceHandle);
-            if (table)
+            if (table) {
               table->GetEntry("mode").SetString(VideoModeToString(event.mode));
+            }
             break;
           }
           case cs::VideoEvent::kSourcePropertyCreated: {
             auto table = GetSourceTable(event.sourceHandle);
-            if (table) PutSourcePropertyValue(table.get(), event, true);
+            if (table) {
+              PutSourcePropertyValue(table.get(), event, true);
+            }
             break;
           }
           case cs::VideoEvent::kSourcePropertyValueUpdated: {
             auto table = GetSourceTable(event.sourceHandle);
-            if (table) PutSourcePropertyValue(table.get(), event, false);
+            if (table) {
+              PutSourcePropertyValue(table.get(), event, false);
+            }
             break;
           }
           case cs::VideoEvent::kSourcePropertyChoicesUpdated: {
             auto table = GetSourceTable(event.sourceHandle);
             if (table) {
-              wpi::SmallString<64> name{"PropertyInfo/"};
-              name += event.name;
-              name += "/choices";
               auto choices =
                   cs::GetEnumPropertyChoices(event.propertyHandle, &status);
-              table->GetEntry(name).SetStringArray(choices);
+              table
+                  ->GetEntry(fmt::format("PropertyInfo/{}/choices", event.name))
+                  .SetStringArray(choices);
             }
             break;
           }
@@ -409,31 +423,35 @@
   // else tries to change it.
   wpi::SmallString<64> buf;
   m_tableListener = nt::NetworkTableInstance::GetDefault().AddEntryListener(
-      kPublishName + wpi::Twine('/'),
+      fmt::format("{}/", kPublishName),
       [=](const nt::EntryNotification& event) {
-        wpi::StringRef relativeKey =
-            event.name.substr(wpi::StringRef(kPublishName).size() + 1);
+        auto relativeKey = wpi::drop_front(
+            event.name, std::string_view{kPublishName}.size() + 1);
 
         // get source (sourceName/...)
         auto subKeyIndex = relativeKey.find('/');
-        if (subKeyIndex == wpi::StringRef::npos) return;
-        wpi::StringRef sourceName = relativeKey.slice(0, subKeyIndex);
+        if (subKeyIndex == std::string_view::npos) {
+          return;
+        }
+        auto sourceName = wpi::slice(relativeKey, 0, subKeyIndex);
         auto sourceIt = m_sources.find(sourceName);
-        if (sourceIt == m_sources.end()) return;
+        if (sourceIt == m_sources.end()) {
+          return;
+        }
 
         // get subkey
-        relativeKey = relativeKey.substr(subKeyIndex + 1);
+        relativeKey.remove_prefix(subKeyIndex + 1);
 
         // handle standard names
-        wpi::StringRef propName;
+        std::string_view propName;
         nt::NetworkTableEntry entry{event.entry};
         if (relativeKey == "mode") {
           // reset to current mode
           entry.SetString(VideoModeToString(sourceIt->second.GetVideoMode()));
           return;
-        } else if (relativeKey.startswith("Property/")) {
+        } else if (wpi::starts_with(relativeKey, "Property/")) {
           propName = relativeKey.substr(9);
-        } else if (relativeKey.startswith("RawProperty/")) {
+        } else if (wpi::starts_with(relativeKey, "RawProperty/")) {
           propName = relativeKey.substr(12);
         } else {
           return;  // ignore
@@ -461,26 +479,23 @@
       NT_NOTIFY_IMMEDIATE | NT_NOTIFY_UPDATE);
 }
 
-CameraServer::CameraServer() : m_impl(new Impl) {}
-
-CameraServer::~CameraServer() {}
-
 cs::UsbCamera CameraServer::StartAutomaticCapture() {
-  cs::UsbCamera camera = StartAutomaticCapture(m_impl->m_defaultUsbDevice++);
+  cs::UsbCamera camera =
+      StartAutomaticCapture(::GetInstance().m_defaultUsbDevice++);
   auto csShared = GetCameraServerShared();
   csShared->ReportUsbCamera(camera.GetHandle());
   return camera;
 }
 
 cs::UsbCamera CameraServer::StartAutomaticCapture(int dev) {
-  cs::UsbCamera camera{"USB Camera " + wpi::Twine(dev), dev};
+  cs::UsbCamera camera{fmt::format("USB Camera {}", dev), dev};
   StartAutomaticCapture(camera);
   auto csShared = GetCameraServerShared();
   csShared->ReportUsbCamera(camera.GetHandle());
   return camera;
 }
 
-cs::UsbCamera CameraServer::StartAutomaticCapture(const wpi::Twine& name,
+cs::UsbCamera CameraServer::StartAutomaticCapture(std::string_view name,
                                                   int dev) {
   cs::UsbCamera camera{name, dev};
   StartAutomaticCapture(camera);
@@ -489,8 +504,8 @@
   return camera;
 }
 
-cs::UsbCamera CameraServer::StartAutomaticCapture(const wpi::Twine& name,
-                                                  const wpi::Twine& path) {
+cs::UsbCamera CameraServer::StartAutomaticCapture(std::string_view name,
+                                                  std::string_view path) {
   cs::UsbCamera camera{name, path};
   StartAutomaticCapture(camera);
   auto csShared = GetCameraServerShared();
@@ -498,7 +513,7 @@
   return camera;
 }
 
-cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& host) {
+cs::AxisCamera CameraServer::AddAxisCamera(std::string_view host) {
   return AddAxisCamera("Axis Camera", host);
 }
 
@@ -510,12 +525,12 @@
   return AddAxisCamera("Axis Camera", host);
 }
 
-cs::AxisCamera CameraServer::AddAxisCamera(wpi::ArrayRef<std::string> hosts) {
+cs::AxisCamera CameraServer::AddAxisCamera(wpi::span<const std::string> hosts) {
   return AddAxisCamera("Axis Camera", hosts);
 }
 
-cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
-                                           const wpi::Twine& host) {
+cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
+                                           std::string_view host) {
   cs::AxisCamera camera{name, host};
   StartAutomaticCapture(camera);
   auto csShared = GetCameraServerShared();
@@ -523,7 +538,7 @@
   return camera;
 }
 
-cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
+cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
                                            const char* host) {
   cs::AxisCamera camera{name, host};
   StartAutomaticCapture(camera);
@@ -532,7 +547,7 @@
   return camera;
 }
 
-cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
+cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
                                            const std::string& host) {
   cs::AxisCamera camera{name, host};
   StartAutomaticCapture(camera);
@@ -541,8 +556,8 @@
   return camera;
 }
 
-cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
-                                           wpi::ArrayRef<std::string> hosts) {
+cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
+                                           wpi::span<const std::string> hosts) {
   cs::AxisCamera camera{name, hosts};
   StartAutomaticCapture(camera);
   auto csShared = GetCameraServerShared();
@@ -550,11 +565,11 @@
   return camera;
 }
 
-cs::MjpegServer CameraServer::AddSwitchedCamera(const wpi::Twine& name) {
+cs::MjpegServer CameraServer::AddSwitchedCamera(std::string_view name) {
   // create a dummy CvSource
   cs::CvSource source{name, cs::VideoMode::PixelFormat::kMJPEG, 160, 120, 30};
   cs::MjpegServer server = StartAutomaticCapture(source);
-  m_impl->m_fixedSources[server.GetHandle()] = source.GetHandle();
+  ::GetInstance().m_fixedSources[server.GetHandle()] = source.GetHandle();
 
   return server;
 }
@@ -562,22 +577,23 @@
 cs::MjpegServer CameraServer::StartAutomaticCapture(
     const cs::VideoSource& camera) {
   AddCamera(camera);
-  auto server = AddServer(wpi::Twine("serve_") + camera.GetName());
+  auto server = AddServer(fmt::format("serve_{}", camera.GetName()));
   server.SetSource(camera);
   return server;
 }
 
 cs::CvSink CameraServer::GetVideo() {
+  auto& inst = ::GetInstance();
   cs::VideoSource source;
   {
     auto csShared = GetCameraServerShared();
-    std::scoped_lock lock(m_impl->m_mutex);
-    if (m_impl->m_primarySourceName.empty()) {
+    std::scoped_lock lock(inst.m_mutex);
+    if (inst.m_primarySourceName.empty()) {
       csShared->SetCameraServerError("no camera available");
       return cs::CvSink{};
     }
-    auto it = m_impl->m_sources.find(m_impl->m_primarySourceName);
-    if (it == m_impl->m_sources.end()) {
+    auto it = inst.m_sources.find(inst.m_primarySourceName);
+    if (it == inst.m_sources.end()) {
       csShared->SetCameraServerError("no camera available");
       return cs::CvSink{};
     }
@@ -587,40 +603,40 @@
 }
 
 cs::CvSink CameraServer::GetVideo(const cs::VideoSource& camera) {
+  auto& inst = ::GetInstance();
   wpi::SmallString<64> name{"opencv_"};
   name += camera.GetName();
 
   {
-    std::scoped_lock lock(m_impl->m_mutex);
-    auto it = m_impl->m_sinks.find(name);
-    if (it != m_impl->m_sinks.end()) {
+    std::scoped_lock lock(inst.m_mutex);
+    auto it = inst.m_sinks.find(name);
+    if (it != inst.m_sinks.end()) {
       auto kind = it->second.GetKind();
       if (kind != cs::VideoSink::kCv) {
         auto csShared = GetCameraServerShared();
-        csShared->SetCameraServerError("expected OpenCV sink, but got " +
-                                       wpi::Twine(kind));
+        csShared->SetCameraServerError("expected OpenCV sink, but got {}",
+                                       kind);
         return cs::CvSink{};
       }
       return *static_cast<cs::CvSink*>(&it->second);
     }
   }
 
-  cs::CvSink newsink{name};
+  cs::CvSink newsink{name.str()};
   newsink.SetSource(camera);
   AddServer(newsink);
   return newsink;
 }
 
-cs::CvSink CameraServer::GetVideo(const wpi::Twine& name) {
-  wpi::SmallString<64> nameBuf;
-  wpi::StringRef nameStr = name.toStringRef(nameBuf);
+cs::CvSink CameraServer::GetVideo(std::string_view name) {
+  auto& inst = ::GetInstance();
   cs::VideoSource source;
   {
-    std::scoped_lock lock(m_impl->m_mutex);
-    auto it = m_impl->m_sources.find(nameStr);
-    if (it == m_impl->m_sources.end()) {
+    std::scoped_lock lock(inst.m_mutex);
+    auto it = inst.m_sources.find(name);
+    if (it == inst.m_sources.end()) {
       auto csShared = GetCameraServerShared();
-      csShared->SetCameraServerError("could not find camera " + nameStr);
+      csShared->SetCameraServerError("could not find camera {}", name);
       return cs::CvSink{};
     }
     source = it->second;
@@ -628,89 +644,99 @@
   return GetVideo(source);
 }
 
-cs::CvSource CameraServer::PutVideo(const wpi::Twine& name, int width,
+cs::CvSource CameraServer::PutVideo(std::string_view name, int width,
                                     int height) {
   cs::CvSource source{name, cs::VideoMode::kMJPEG, width, height, 30};
   StartAutomaticCapture(source);
   return source;
 }
 
-cs::MjpegServer CameraServer::AddServer(const wpi::Twine& name) {
+cs::MjpegServer CameraServer::AddServer(std::string_view name) {
+  auto& inst = ::GetInstance();
   int port;
   {
-    std::scoped_lock lock(m_impl->m_mutex);
-    port = m_impl->m_nextPort++;
+    std::scoped_lock lock(inst.m_mutex);
+    port = inst.m_nextPort++;
   }
   return AddServer(name, port);
 }
 
-cs::MjpegServer CameraServer::AddServer(const wpi::Twine& name, int port) {
+cs::MjpegServer CameraServer::AddServer(std::string_view name, int port) {
   cs::MjpegServer server{name, port};
   AddServer(server);
   return server;
 }
 
 void CameraServer::AddServer(const cs::VideoSink& server) {
-  std::scoped_lock lock(m_impl->m_mutex);
-  m_impl->m_sinks.try_emplace(server.GetName(), server);
+  auto& inst = ::GetInstance();
+  std::scoped_lock lock(inst.m_mutex);
+  inst.m_sinks.try_emplace(server.GetName(), server);
 }
 
-void CameraServer::RemoveServer(const wpi::Twine& name) {
-  std::scoped_lock lock(m_impl->m_mutex);
-  wpi::SmallString<64> nameBuf;
-  m_impl->m_sinks.erase(name.toStringRef(nameBuf));
+void CameraServer::RemoveServer(std::string_view name) {
+  auto& inst = ::GetInstance();
+  std::scoped_lock lock(inst.m_mutex);
+  inst.m_sinks.erase(name);
 }
 
 cs::VideoSink CameraServer::GetServer() {
-  wpi::SmallString<64> name;
+  auto& inst = ::GetInstance();
+  std::string name;
   {
-    std::scoped_lock lock(m_impl->m_mutex);
-    if (m_impl->m_primarySourceName.empty()) {
+    std::scoped_lock lock(inst.m_mutex);
+    if (inst.m_primarySourceName.empty()) {
       auto csShared = GetCameraServerShared();
       csShared->SetCameraServerError("no camera available");
       return cs::VideoSink{};
     }
-    name = "serve_";
-    name += m_impl->m_primarySourceName;
+    name = fmt::format("serve_{}", inst.m_primarySourceName);
   }
   return GetServer(name);
 }
 
-cs::VideoSink CameraServer::GetServer(const wpi::Twine& name) {
-  wpi::SmallString<64> nameBuf;
-  wpi::StringRef nameStr = name.toStringRef(nameBuf);
-  std::scoped_lock lock(m_impl->m_mutex);
-  auto it = m_impl->m_sinks.find(nameStr);
-  if (it == m_impl->m_sinks.end()) {
+cs::VideoSink CameraServer::GetServer(std::string_view name) {
+  auto& inst = ::GetInstance();
+  std::scoped_lock lock(inst.m_mutex);
+  auto it = inst.m_sinks.find(name);
+  if (it == inst.m_sinks.end()) {
     auto csShared = GetCameraServerShared();
-    csShared->SetCameraServerError("could not find server " + nameStr);
+    csShared->SetCameraServerError("could not find server {}", name);
     return cs::VideoSink{};
   }
   return it->second;
 }
 
 void CameraServer::AddCamera(const cs::VideoSource& camera) {
+  auto& inst = ::GetInstance();
   std::string name = camera.GetName();
-  std::scoped_lock lock(m_impl->m_mutex);
-  if (m_impl->m_primarySourceName.empty()) m_impl->m_primarySourceName = name;
-  m_impl->m_sources.try_emplace(name, camera);
+  std::scoped_lock lock(inst.m_mutex);
+  if (inst.m_primarySourceName.empty()) {
+    inst.m_primarySourceName = name;
+  }
+  inst.m_sources.try_emplace(name, camera);
 }
 
-void CameraServer::RemoveCamera(const wpi::Twine& name) {
-  std::scoped_lock lock(m_impl->m_mutex);
-  wpi::SmallString<64> nameBuf;
-  m_impl->m_sources.erase(name.toStringRef(nameBuf));
+void CameraServer::RemoveCamera(std::string_view name) {
+  auto& inst = ::GetInstance();
+  std::scoped_lock lock(inst.m_mutex);
+  inst.m_sources.erase(name);
 }
 
 void CameraServer::SetSize(int size) {
-  std::scoped_lock lock(m_impl->m_mutex);
-  if (m_impl->m_primarySourceName.empty()) return;
-  auto it = m_impl->m_sources.find(m_impl->m_primarySourceName);
-  if (it == m_impl->m_sources.end()) return;
-  if (size == kSize160x120)
+  auto& inst = ::GetInstance();
+  std::scoped_lock lock(inst.m_mutex);
+  if (inst.m_primarySourceName.empty()) {
+    return;
+  }
+  auto it = inst.m_sources.find(inst.m_primarySourceName);
+  if (it == inst.m_sources.end()) {
+    return;
+  }
+  if (size == kSize160x120) {
     it->second.SetResolution(160, 120);
-  else if (size == kSize320x240)
+  } else if (size == kSize320x240) {
     it->second.SetResolution(320, 240);
-  else if (size == kSize640x480)
+  } else if (size == kSize640x480) {
     it->second.SetResolution(640, 480);
+  }
 }
diff --git a/cameraserver/src/main/native/cpp/cameraserver/CameraServerShared.cpp b/cameraserver/src/main/native/cpp/cameraserver/CameraServerShared.cpp
index 7d30d28..6d1ebc2 100644
--- a/cameraserver/src/main/native/cpp/cameraserver/CameraServerShared.cpp
+++ b/cameraserver/src/main/native/cpp/cameraserver/CameraServerShared.cpp
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #include "cameraserver/CameraServerShared.h"
 
@@ -15,9 +12,12 @@
   void ReportUsbCamera(int id) override {}
   void ReportAxisCamera(int id) override {}
   void ReportVideoServer(int id) override {}
-  void SetCameraServerError(const wpi::Twine& error) override {}
-  void SetVisionRunnerError(const wpi::Twine& error) override {}
-  void ReportDriverStationError(const wpi::Twine& error) override {}
+  void SetCameraServerErrorV(fmt::string_view format,
+                             fmt::format_args args) override {}
+  void SetVisionRunnerErrorV(fmt::string_view format,
+                             fmt::format_args args) override {}
+  void ReportDriverStationErrorV(fmt::string_view format,
+                                 fmt::format_args args) override {}
   std::pair<std::thread::id, bool> GetRobotMainThreadId() const override {
     return std::make_pair(std::thread::id(), false);
   }
diff --git a/cameraserver/src/main/native/cpp/vision/VisionRunner.cpp b/cameraserver/src/main/native/cpp/vision/VisionRunner.cpp
index 9896bbd..b55325a 100644
--- a/cameraserver/src/main/native/cpp/vision/VisionRunner.cpp
+++ b/cameraserver/src/main/native/cpp/vision/VisionRunner.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 "vision/VisionRunner.h"
 
@@ -23,7 +20,7 @@
 }
 
 // Located here and not in header due to cv::Mat forward declaration.
-VisionRunnerBase::~VisionRunnerBase() {}
+VisionRunnerBase::~VisionRunnerBase() = default;
 
 void VisionRunnerBase::RunOnce() {
   auto csShared = frc::GetCameraServerShared();
@@ -36,7 +33,7 @@
   auto frameTime = m_cvSink.GrabFrame(*m_image);
   if (frameTime == 0) {
     auto error = m_cvSink.GetError();
-    csShared->ReportDriverStationError(error);
+    csShared->ReportDriverStationError(error.c_str());
   } else {
     DoProcess(*m_image);
   }
@@ -56,4 +53,6 @@
   }
 }
 
-void VisionRunnerBase::Stop() { m_enabled = false; }
+void VisionRunnerBase::Stop() {
+  m_enabled = false;
+}
diff --git a/cameraserver/src/main/native/include/cameraserver/CameraServer.h b/cameraserver/src/main/native/include/cameraserver/CameraServer.h
index 8f384fd..6d087e9 100644
--- a/cameraserver/src/main/native/include/cameraserver/CameraServer.h
+++ b/cameraserver/src/main/native/include/cameraserver/CameraServer.h
@@ -1,19 +1,16 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2014-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
 #include <stdint.h>
 
-#include <memory>
 #include <string>
+#include <string_view>
 
-#include <wpi/ArrayRef.h>
-#include <wpi/Twine.h>
+#include <wpi/deprecated.h>
+#include <wpi/span.h>
 
 #include "cscore.h"
 #include "cscore_cv.h"
@@ -34,7 +31,9 @@
 
   /**
    * Get the CameraServer instance.
+   * @deprecated Use the static methods
    */
+  WPI_DEPRECATED("Use static methods")
   static CameraServer* GetInstance();
 
   /**
@@ -48,7 +47,7 @@
    * with device 0, creating a camera named "USB Camera 0".  Subsequent calls
    * increment the device number (e.g. 1, 2, etc).
    */
-  cs::UsbCamera StartAutomaticCapture();
+  static cs::UsbCamera StartAutomaticCapture();
 
   /**
    * Start automatically capturing images to send to the dashboard.
@@ -58,7 +57,7 @@
    *
    * @param dev The device number of the camera interface
    */
-  cs::UsbCamera StartAutomaticCapture(int dev);
+  static cs::UsbCamera StartAutomaticCapture(int dev);
 
   /**
    * Start automatically capturing images to send to the dashboard.
@@ -66,7 +65,7 @@
    * @param name The name to give the camera
    * @param dev  The device number of the camera interface
    */
-  cs::UsbCamera StartAutomaticCapture(const wpi::Twine& name, int dev);
+  static cs::UsbCamera StartAutomaticCapture(std::string_view name, int dev);
 
   /**
    * Start automatically capturing images to send to the dashboard.
@@ -74,8 +73,8 @@
    * @param name The name to give the camera
    * @param path The device path (e.g. "/dev/video0") of the camera
    */
-  cs::UsbCamera StartAutomaticCapture(const wpi::Twine& name,
-                                      const wpi::Twine& path);
+  static cs::UsbCamera StartAutomaticCapture(std::string_view name,
+                                             std::string_view path);
 
   /**
    * Start automatically capturing images to send to the dashboard from
@@ -83,7 +82,7 @@
    *
    * @param camera Camera
    */
-  cs::MjpegServer StartAutomaticCapture(const cs::VideoSource& camera);
+  static cs::MjpegServer StartAutomaticCapture(const cs::VideoSource& camera);
 
   /**
    * Adds an Axis IP camera.
@@ -92,7 +91,7 @@
    *
    * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
    */
-  cs::AxisCamera AddAxisCamera(const wpi::Twine& host);
+  static cs::AxisCamera AddAxisCamera(std::string_view host);
 
   /**
    * Adds an Axis IP camera.
@@ -101,7 +100,7 @@
    *
    * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
    */
-  cs::AxisCamera AddAxisCamera(const char* host);
+  static cs::AxisCamera AddAxisCamera(const char* host);
 
   /**
    * Adds an Axis IP camera.
@@ -110,7 +109,7 @@
    *
    * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
    */
-  cs::AxisCamera AddAxisCamera(const std::string& host);
+  static cs::AxisCamera AddAxisCamera(const std::string& host);
 
   /**
    * Adds an Axis IP camera.
@@ -119,7 +118,7 @@
    *
    * @param hosts Array of Camera host IPs/DNS names
    */
-  cs::AxisCamera AddAxisCamera(wpi::ArrayRef<std::string> hosts);
+  static cs::AxisCamera AddAxisCamera(wpi::span<const std::string> hosts);
 
   /**
    * Adds an Axis IP camera.
@@ -129,7 +128,7 @@
    * @param hosts Array of Camera host IPs/DNS names
    */
   template <typename T>
-  cs::AxisCamera AddAxisCamera(std::initializer_list<T> hosts);
+  static cs::AxisCamera AddAxisCamera(std::initializer_list<T> hosts);
 
   /**
    * Adds an Axis IP camera.
@@ -137,7 +136,8 @@
    * @param name The name to give the camera
    * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
    */
-  cs::AxisCamera AddAxisCamera(const wpi::Twine& name, const wpi::Twine& host);
+  static cs::AxisCamera AddAxisCamera(std::string_view name,
+                                      std::string_view host);
 
   /**
    * Adds an Axis IP camera.
@@ -145,7 +145,7 @@
    * @param name The name to give the camera
    * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
    */
-  cs::AxisCamera AddAxisCamera(const wpi::Twine& name, const char* host);
+  static cs::AxisCamera AddAxisCamera(std::string_view name, const char* host);
 
   /**
    * Adds an Axis IP camera.
@@ -153,7 +153,8 @@
    * @param name The name to give the camera
    * @param host Camera host IP or DNS name (e.g. "10.x.y.11")
    */
-  cs::AxisCamera AddAxisCamera(const wpi::Twine& name, const std::string& host);
+  static cs::AxisCamera AddAxisCamera(std::string_view name,
+                                      const std::string& host);
 
   /**
    * Adds an Axis IP camera.
@@ -161,8 +162,8 @@
    * @param name The name to give the camera
    * @param hosts Array of Camera host IPs/DNS names
    */
-  cs::AxisCamera AddAxisCamera(const wpi::Twine& name,
-                               wpi::ArrayRef<std::string> hosts);
+  static cs::AxisCamera AddAxisCamera(std::string_view name,
+                                      wpi::span<const std::string> hosts);
 
   /**
    * Adds an Axis IP camera.
@@ -171,8 +172,8 @@
    * @param hosts Array of Camera host IPs/DNS names
    */
   template <typename T>
-  cs::AxisCamera AddAxisCamera(const wpi::Twine& name,
-                               std::initializer_list<T> hosts);
+  static cs::AxisCamera AddAxisCamera(std::string_view name,
+                                      std::initializer_list<T> hosts);
 
   /**
    * Adds a virtual camera for switching between two streams.  Unlike the
@@ -180,7 +181,7 @@
    * VideoSource.  Calling SetSource() on the returned object can be used
    * to switch the actual source of the stream.
    */
-  cs::MjpegServer AddSwitchedCamera(const wpi::Twine& name);
+  static cs::MjpegServer AddSwitchedCamera(std::string_view name);
 
   /**
    * Get OpenCV access to the primary camera feed.  This allows you to
@@ -189,7 +190,7 @@
    * <p>This is only valid to call after a camera feed has been added
    * with startAutomaticCapture() or addServer().
    */
-  cs::CvSink GetVideo();
+  static cs::CvSink GetVideo();
 
   /**
    * Get OpenCV access to the specified camera.  This allows you to get
@@ -197,7 +198,7 @@
    *
    * @param camera Camera (e.g. as returned by startAutomaticCapture).
    */
-  cs::CvSink GetVideo(const cs::VideoSource& camera);
+  static cs::CvSink GetVideo(const cs::VideoSource& camera);
 
   /**
    * Get OpenCV access to the specified camera.  This allows you to get
@@ -205,7 +206,7 @@
    *
    * @param name Camera name
    */
-  cs::CvSink GetVideo(const wpi::Twine& name);
+  static cs::CvSink GetVideo(std::string_view name);
 
   /**
    * Create a MJPEG stream with OpenCV input. This can be called to pass custom
@@ -215,35 +216,36 @@
    * @param width Width of the image being sent
    * @param height Height of the image being sent
    */
-  cs::CvSource PutVideo(const wpi::Twine& name, int width, int height);
+  static cs::CvSource PutVideo(std::string_view name, int width, int height);
 
   /**
    * Adds a MJPEG server at the next available port.
    *
    * @param name Server name
    */
-  cs::MjpegServer AddServer(const wpi::Twine& name);
+  static cs::MjpegServer AddServer(std::string_view name);
 
   /**
    * Adds a MJPEG server.
    *
    * @param name Server name
+   * @param port Port number
    */
-  cs::MjpegServer AddServer(const wpi::Twine& name, int port);
+  static cs::MjpegServer AddServer(std::string_view name, int port);
 
   /**
    * Adds an already created server.
    *
    * @param server Server
    */
-  void AddServer(const cs::VideoSink& server);
+  static void AddServer(const cs::VideoSink& server);
 
   /**
    * Removes a server by name.
    *
    * @param name Server name
    */
-  void RemoveServer(const wpi::Twine& name);
+  static void RemoveServer(std::string_view name);
 
   /**
    * Get server for the primary camera feed.
@@ -251,28 +253,28 @@
    * This is only valid to call after a camera feed has been added with
    * StartAutomaticCapture() or AddServer().
    */
-  cs::VideoSink GetServer();
+  static cs::VideoSink GetServer();
 
   /**
    * Gets a server by name.
    *
    * @param name Server name
    */
-  cs::VideoSink GetServer(const wpi::Twine& name);
+  static cs::VideoSink GetServer(std::string_view name);
 
   /**
    * Adds an already created camera.
    *
    * @param camera Camera
    */
-  void AddCamera(const cs::VideoSource& camera);
+  static void AddCamera(const cs::VideoSource& camera);
 
   /**
    * Removes a camera by name.
    *
    * @param name Camera name
    */
-  void RemoveCamera(const wpi::Twine& name);
+  static void RemoveCamera(std::string_view name);
 
   /**
    * Sets the size of the image to use. Use the public kSize constants to set
@@ -283,14 +285,10 @@
    *             StartAutomaticCapture() instead.
    * @param size The size to use
    */
-  void SetSize(int size);
+  static void SetSize(int size);
 
  private:
-  CameraServer();
-  ~CameraServer();
-
-  struct Impl;
-  std::unique_ptr<Impl> m_impl;
+  CameraServer() = default;
 };
 
 }  // namespace frc
diff --git a/cameraserver/src/main/native/include/cameraserver/CameraServer.inc b/cameraserver/src/main/native/include/cameraserver/CameraServer.inc
index 5daf29f..8c8ec21 100644
--- a/cameraserver/src/main/native/include/cameraserver/CameraServer.inc
+++ b/cameraserver/src/main/native/include/cameraserver/CameraServer.inc
@@ -1,15 +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.
 
 #pragma once
 
 #include <string>
 #include <vector>
 
+#include "cameraserver/CameraServer.h"
+
 namespace frc {
 
 template <typename T>
@@ -20,10 +19,12 @@
 
 template <typename T>
 inline cs::AxisCamera CameraServer::AddAxisCamera(
-    const wpi::Twine& name, std::initializer_list<T> hosts) {
+    std::string_view name, std::initializer_list<T> hosts) {
   std::vector<std::string> vec;
   vec.reserve(hosts.size());
-  for (const auto& host : hosts) vec.emplace_back(host);
+  for (const auto& host : hosts) {
+    vec.emplace_back(host);
+  }
   return AddAxisCamera(name, vec);
 }
 
diff --git a/cameraserver/src/main/native/include/cameraserver/CameraServerShared.h b/cameraserver/src/main/native/include/cameraserver/CameraServerShared.h
index cb72c9b..f6c6ae7 100644
--- a/cameraserver/src/main/native/include/cameraserver/CameraServerShared.h
+++ b/cameraserver/src/main/native/include/cameraserver/CameraServerShared.h
@@ -1,9 +1,6 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018-2019 FIRST. All Rights Reserved.                        */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
 #pragma once
 
@@ -11,7 +8,7 @@
 #include <thread>
 #include <utility>
 
-#include <wpi/Twine.h>
+#include <fmt/format.h>
 
 namespace frc {
 class CameraServerShared {
@@ -20,10 +17,31 @@
   virtual void ReportUsbCamera(int id) = 0;
   virtual void ReportAxisCamera(int id) = 0;
   virtual void ReportVideoServer(int id) = 0;
-  virtual void SetCameraServerError(const wpi::Twine& error) = 0;
-  virtual void SetVisionRunnerError(const wpi::Twine& error) = 0;
-  virtual void ReportDriverStationError(const wpi::Twine& error) = 0;
+  virtual void SetCameraServerErrorV(fmt::string_view format,
+                                     fmt::format_args args) = 0;
+  virtual void SetVisionRunnerErrorV(fmt::string_view format,
+                                     fmt::format_args args) = 0;
+  virtual void ReportDriverStationErrorV(fmt::string_view format,
+                                         fmt::format_args args) = 0;
   virtual std::pair<std::thread::id, bool> GetRobotMainThreadId() const = 0;
+
+  template <typename S, typename... Args>
+  inline void SetCameraServerError(const S& format, Args&&... args) {
+    SetCameraServerErrorV(format,
+                          fmt::make_args_checked<Args...>(format, args...));
+  }
+
+  template <typename S, typename... Args>
+  inline void SetVisionRunnerError(const S& format, Args&&... args) {
+    SetVisionRunnerErrorV(format,
+                          fmt::make_args_checked<Args...>(format, args...));
+  }
+
+  template <typename S, typename... Args>
+  inline void ReportDriverStationError(const S& format, Args&&... args) {
+    ReportDriverStationErrorV(format,
+                              fmt::make_args_checked<Args...>(format, args...));
+  }
 };
 
 CameraServerShared* GetCameraServerShared();
diff --git a/cameraserver/src/main/native/include/vision/VisionPipeline.h b/cameraserver/src/main/native/include/vision/VisionPipeline.h
index de8e54c..954906b 100644
--- a/cameraserver/src/main/native/include/vision/VisionPipeline.h
+++ b/cameraserver/src/main/native/include/vision/VisionPipeline.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/cameraserver/src/main/native/include/vision/VisionRunner.h b/cameraserver/src/main/native/include/vision/VisionRunner.h
index 610ac4d..6e6e93a 100644
--- a/cameraserver/src/main/native/include/vision/VisionRunner.h
+++ b/cameraserver/src/main/native/include/vision/VisionRunner.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
 
@@ -47,14 +44,14 @@
    *
    * <p>This method is exposed to allow teams to add additional functionality or
    * have their own ways to run the pipeline. Most teams, however, should just
-   * use {@link #runForever} in its own thread using a std::thread.</p>
+   * use RunForever() in its own thread using a std::thread.</p>
    */
   void RunOnce();
 
   /**
-   * A convenience method that calls {@link #runOnce()} in an infinite loop.
-   * This must be run in a dedicated thread, and cannot be used in the main
-   * robot thread because it will freeze the robot program.
+   * A convenience method that calls runOnce() in an infinite loop. This must be
+   * run in a dedicated thread, and cannot be used in the main robot thread
+   * because it will freeze the robot program.
    *
    * <strong>Do not call this method directly from the main thread.</strong>
    */
diff --git a/cameraserver/src/main/native/include/vision/VisionRunner.inc b/cameraserver/src/main/native/include/vision/VisionRunner.inc
index 1a38048..9a195ff 100644
--- a/cameraserver/src/main/native/include/vision/VisionRunner.inc
+++ b/cameraserver/src/main/native/include/vision/VisionRunner.inc
@@ -1,12 +1,11 @@
-/*----------------------------------------------------------------------------*/
-/* 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 "vision/VisionRunner.h"
+
 namespace frc {
 
 /**
diff --git a/cameraserver/src/test/native/cpp/main.cpp b/cameraserver/src/test/native/cpp/main.cpp
index f07ede3..b36f826 100644
--- a/cameraserver/src/test/native/cpp/main.cpp
+++ b/cameraserver/src/test/native/cpp/main.cpp
@@ -1,8 +1,7 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved.                             */
-/* Open Source Software - may be modified and shared by FRC teams. The code   */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project.                                                               */
-/*----------------------------------------------------------------------------*/
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
 
-int main() { return 0; }
+int main() {
+  return 0;
+}