This adds support for two serialization formats for complex data types:
- Protobuf for complex objects with variable length internals that need forward and backward wire compatibility (lower speed, more flexible)
- Raw struct (ByteBuffer-style) for fixed-length objects (higher speed, less flexible)
Deserialization can be done either by creating a new object (for immutable objects) or overwriting the contents of an existing object (for mutable objects).
Implementing classes should provide inner classes that implement the Protobuf or Struct interface (in Java) or specialize the wpi::Protobuf or wpi::Struct struct (in C++). It is possible for classes to implement both. If the class itself does not implement serialization, it's possible for third parties/users to provide an implementation instead.
Uses the Google protobuf implementation for C++ and the QuickBuffers alternative protobuf implementation for Java.
fmtlib uses consteval format string processing, which makes it more
efficient than std::snprintf().
snprintf()s in libuv, mpack, processstarter, and wpigui were left alone.
processstarter uses stdlib only, and wpigui only depends on imgui.
fmt::format_to_n() is analogous to std::format_to_n()
(https://en.cppreference.com/w/cpp/utility/format/format_to_n)
wpi::format_to_n_c_str() is a wrapper which adds the trailing NUL.
The following source code changes were required:
* Whitespace changes from spotless
* PMD warning suppressions for utility class tests
* PMD warning rename from "BeanMembersShouldSerialize" to
"NonSerializableClass"
* Declared more class members as final
Current timestamp read code uses FPGA register reads. Through testing,
this read was slower then clock_gettime by about 4-5x. However, another
method of reading the FPGA time is available, using HMB. HMB
is memory mapped IO from RAM to the FPGA. So to code side,
reading the value is just a memory barrier and a memory read.
There is some latency on the write side, so a very small artifical delay
(5us) is added to avoid register reads such as interrupts being ahead
of current timestamps, which could cause issues.
Below is read times for 1000 calls to clock_gettime, register reads and
hmb reads.
```
Clock: Rise 1.72939400 s Fall 1.72990700 s Delta 0.00051300 s
FPGA : Rise 1.72999000 s Fall 1.73429300 s Delta 0.00430300 s
HMB : Rise 1.73466800 s Fall 1.73481900 s Delta 0.00015100 s
```
Also add full HMB struct to HAL for future usage.
This works around an exit race with wpi::Now() on Rio; it was overridden
to call HAL_GetFPGATime(), which calls chipobject, but on exit, because
there was not a library dependency, the chipobject could be destroyed
prior to wpiutil/wpinet being shut down.