Compare commits

...

156 Commits

Author SHA1 Message Date
Gold856
3fddf71c47 [build] Remove Javadoc fonts (#8837)
Javadoc now includes 4 MB of fonts for every Javadoc JAR, which we have
18 of, which causes unnecessary bloat to the installer size. This
disables the inclusion of those fonts, using the built-in fallback
included in the Javadoc stylesheet. This also increases the default font
size by 10% after polling the FTC Discord resulted in people asking for
a bigger font.
2026-04-29 14:57:31 -07:00
Gold856
668124e0fd [build] Compress shared object debug info (#8835)
This saves a huge amount of space when they're unzipped for robot
projects, while not increasing artifact size.
2026-04-29 12:14:11 -07:00
Thad House
433c7f00ad [wpilib] Fix jar loading in folder with spaces (#8836) 2026-04-29 12:11:19 -07:00
Thad House
94443c8e84 [wpilib] Fix OpModeRobot initialization (#8834)
There were 3 cases failing before.

1. An OpModeRobot with no annotation.
2. An OpModeRobot with an annotation but a parameterless constructor.
3. An OpMode with a UserControls constructor

This PR solves both of these issues. The first one is solved by adding
the null check before setting the user controls instance. That one will
never have an opmode instance.

The second one is solved by falling back to a parameterless constructor
if one with a parameter is not found.

The 3rd one is solved by using the annotation type rather than the
instance for constructor lookup.

Also fixes ExpansionHubSample's missing annotations.
2026-04-28 12:54:10 -07:00
Gold856
3bf67edc34 [build] Refactor zip base name generation for consistency (#8831)
Right now, the `zipBaseName` variable in various publish.gradle files
contains the group ID and artifact ID for use by the combiner, however,
they are also duplicated in `artifactGroupId` and `baseArtifactId`,
leading to potential mistakes if they aren't updated together. This
fixes that by adding a new utility function `makeZipBaseName` to
automatically create the right name given a group ID and artifact ID.
This also fixes publishing for thirdparty subprojects, which didn't
update `zipBaseName`.
2026-04-27 11:46:11 -07:00
sciencewhiz
29beacbefe Fix some Test Mode references to Utility (NFC) (#8827) 2026-04-26 22:32:50 -07:00
Gold856
8d30131fce [build] Update native-utils, OpenCV, libssh (#8818) 2026-04-26 22:31:14 -07:00
Kevin Cooney
657d4d9b58 [ntcore,wpilib] Fix tsan errors in tests that add NT listeners (#8713) 2026-04-26 16:40:46 -07:00
Gold856
97d0b15f7d Add README files for some subprojects and update various other docs (#8640)
Adds a section on design philosophy so we have something to point to
when people suggest features that aren't compatible with the way WPILib
is designed. Fixes some missed reorg changes (although the native-utils
link intentionally points to main as to be up-to-date in the future) and
generally cleans up any outdated information. Also includes wording
about supporting FTC. Per discussion in Slack, the LabVIEW wording has
been removed, and anything to do with LabVIEW is going to have to be
NI's job. And pursuant to #2757 and #5331, additional (light) developer
documentation has been added to some subprojects, mostly being a quick
summary of the what the project does and what it's for (or not for).

---------

Co-authored-by: sciencewhiz <sciencewhiz@users.noreply.github.com>
Co-authored-by: Joseph Eng <91924258+KangarooKoala@users.noreply.github.com>
2026-04-26 16:39:26 -07:00
PJ Reiniger
a695865781 [bazel] Update copybara scripts (#8822)
I've been running my copybara syncs from this branch for a long time.
Finally deciding to PR it.

The biggest update was due to `mostrobotpy` absorbing the commands,
examples, and pyfrc libraries, but I also added in hooks to "enable" the
flakey `xfail` tests on the allwpilib side, and the ability to run
verbose or force push updates.
2026-04-26 15:14:58 -07:00
sciencewhiz
c511fcc160 Update a few misc FRC references (NFC) (#8824) 2026-04-26 15:09:14 -07:00
PJ Reiniger
e5980b46ef [copybara] Sync with mostrobotpy (#8820)
GitOrigin-RevId: f03f29e57af22a74b680873090028b9c9f5c8063
2026-04-26 08:25:15 -07:00
Tyler Veness
af7d68e993 [wpiutil] Use C++23 stacktrace library on Windows (#6839)
This lets us remove the unmaintained StackWalker library and its hacky
upstream_utils script.

@Gold856 reported that StackWalker gives blank stacktraces:
https://discord.com/channels/176186766946992128/368993897495527424/1261940029287301150.
They also reported an earlier version of this PR giving the following
stacktrace instead:
```
D:\allwpilib\developerRobot\src\main\native\cpp\Robot.cpp(18): developerRobotCpp!Robot::RobotInit+0xB6
D:\allwpilib\wpilibc\src\main\native\cpp\TimedRobot.cpp(22): wpilibcd!frc::TimedRobot::StartCompetition+0x4F
D:\allwpilib\wpilibc\src\main\native\include\frc\RobotBase.h(36): developerRobotCpp!frc::impl::RunRobot<Robot>+0xC8
D:\allwpilib\wpilibc\src\main\native\include\frc\RobotBase.h(106): developerRobotCpp!frc::StartRobot<Robot>+0x17E
D:\allwpilib\developerRobot\src\main\native\cpp\Robot.cpp(60): developerRobotCpp!main+0xB
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(79): developerRobotCpp!invoke_main+0x39
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(288): developerRobotCpp!__scrt_common_main_seh+0x132
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(331): developerRobotCpp!__scrt_common_main+0xE
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp(17): developerRobotCpp!mainCRTStartup+0xE
KERNEL32!BaseThreadInitThunk+0x1D
ntdll!RtlUserThreadStart+0x28
```
2026-04-26 00:15:39 -07:00
sciencewhiz
880cfd60c4 Update vendordeps wpilibYear to alpha 5 (#8817) 2026-04-25 21:15:54 -07:00
Thad House
a3968faa57 [examples] Add an ExpansionHubSample example (#8810) 2026-04-25 15:43:24 -07:00
sciencewhiz
6aa1611959 [examples] Add a Hatchbot Commands v3 example (#8809)
This is adapted from the work that @Starlight220 did here:
https://github.com/SamCarlberg/allwpilib/pull/5

---------

Co-authored-by: Starlight220 <53231611+Starlight220@users.noreply.github.com>
2026-04-25 15:06:26 -07:00
Gold856
35e8abedeb Don't force public variables to use Hungarian notation (#8774)
People generally have expressed a dislike for the Hungarian notation
used in member variables, especially in examples/templates, and our
styleguide shouldn't be forced on downstream consumers, so this removes
all Hungarian notation from the examples/templates.

There are _some_ benefits to Hungarian for private member variables
(like knowing what's a member vs. local in a PR review) so we'll keep
private member variables the same for now, but public variables should
no longer use Hungarian notation, since it looks much worse. A new PMD
XPath rule has been added to accomplish this goal. Some other
non-compliant variables were fixed for the new rule.
2026-04-25 11:32:08 -07:00
PJ Reiniger
e7e51c9c05 [bazel][ci] Add CI action to generate pregen patch (#8816)
There were complaints about no patch files being created from CI when
the examples pre-gen fails for people who don't build with bazel. This
adds a new action step to run just the non-robotpy pregen.

I also added an argument to the diff tests to make it a unified diff,
which might make it easier to hand fix.
2026-04-25 11:06:02 -07:00
David Vo
2edef821f9 [bazel] Colocate Doxygen version declarations (#8806)
Since we currently have both a Bazel build and Gradle build, we need to
keep the Doxygen versions in sync between the two.


40188d9cc6/docs/build.gradle (L71)

It's awkward that these are in very disjoint parts of the repo. This
puts them in the same directory so it's more obvious it should be kept
in sync.
2026-04-24 20:06:15 -07:00
Zach Harel
3bf3060ff5 [wpilib] Separate ExpansionHubServo into separate Servo and CRServo classes (#8770)
This removes the confusion of the `ExpansionHubServo` class serving both
purposes, and thus having a `set` method that functions as `setPosition`
when in servo mode and `setThrottle` when not in continuous mode. It
also removes the `setContinuousRotationMethod` which could be confused
for a method that switches the actual servo firmware itself from servo
to continuous mode, which is not a thing that is physically possible I
think.

---------

Signed-off-by: Zach Harel <zach@zharel.me>
2026-04-24 20:03:24 -07:00
Alan Everett
ded1937fcf [build] Update QuickBuffers to 1.3.3 for Bazel builds (#8811)
Continuation of #6072, this fixes a cross-project bug in QuickBuffers.
Needed for #8776.
2026-04-24 19:21:19 -07:00
Zach Harel
a6425d3e1e [wpilib] DriverStation: Add usage reporting for opmodes (#8761) 2026-04-24 19:20:45 -07:00
PJ Reiniger
68a8ebfc81 [robotpy] Fixup problems during stubgen (#8781)
Part of the `semiwrap` process that hasn't been ported over yet is
generating pyi stubs. It is possible to not have your semiwrap setup
correctly and "leak" native types into the generated python docstrings,
which causes the process to
[fail](https://github.com/pjreiniger/mostrobotpy/actions/runs/24618640845/job/71985311682#step:12:3652).
semiwrap also has a tool you can run, 'create-imports' that will read
the symbols from a build pybind library and automatically create and
sort the imports in the `__init__.py` file. This step is not enforced by
CI, which is why it hasn't been failing in `mostrobotpy` land.

This PR fixes the stubgen problems and runs reorganizes the imports. I
will have a follow up PR that can bring these automatically into the
build system after this lands. I'd do a fancy new `gh stack` but I can't
figure out if it works on forks.
2026-04-24 14:59:31 -07:00
Peter Johnson
d539e06b4f [wpinet] DsClient: Use new port which provides IP in dotted quad format (#8807) 2026-04-24 13:15:07 -07:00
David Vo
163cfaa027 [ci] Enable Bazel colored output (#8808) 2026-04-24 13:14:34 -07:00
Peter Johnson
40188d9cc6 [glass] Plot: Fix weight and marker settings (#8805)
Line weight needed to default to 1.0.
Marker added an "auto" setting and now starts at -2.

Fixes #8802.
2026-04-24 08:03:16 -07:00
Peter Johnson
a8b827af54 [wpigui] Rename ini setting from userScale to userScaling (#8804)
This avoids very small text resulting from an upgrade.
2026-04-24 08:02:56 -07:00
Peter Johnson
5703f608d7 [wpiutil] Struct: fix is_constexpr check in constexpr functions (#8798)
Capturing the info parameter pack explicitly is required for the
is_constexpr check to work.

Add some basic tests.

Fixes #8789.
2026-04-24 08:02:27 -07:00
Gold856
d893d44e37 [wpimath] Mark all geometry classes as final (#8790)
In Java, these are likely to become value classes in the future.

Make C++ final for consistency.
2026-04-23 22:55:54 -07:00
Gold856
1586dcf385 [wpimath] Fix incorrect C++ return docs in Pose3d and Translation3d (#8793) 2026-04-23 22:53:29 -07:00
Gold856
930340e8f0 [build] Always run Checkstyle after spotlessApply (#8794)
This avoids issues where Checkstyle will error on line length by having
Spotless run first and fix up line lengths before Checkstyle sees the
files.
2026-04-23 22:52:19 -07:00
Zach Harel
7fc8845424 [wpilib] separate expansion hub position and velocity constants (#8791)
this is because position and velocity control follow different rules;
see #8773

Signed-off-by: Zach Harel <zach@zharel.me>
2026-04-23 17:40:52 -07:00
Sam Carlberg
44b9545f30 [epilogue] Use full class names in static logger fields (#8786)
This prevents conflicts when multiple classes with the same simple name
exist in separate packages
2026-04-21 22:24:24 -07:00
Peter Johnson
ab00aac960 [hal,wpilib] Rename "Test" robot mode to "Utility" (#8782)
The "Utility" name better matches its intended generic use case and
avoids overloaded terminology with unit testing (e.g. the need to name
the opmode annotation `@TestOpMode`).

The driver station will also be updated to reflect this change.
2026-04-20 20:29:25 -07:00
Peter Johnson
14d14e4ebc [hal] Prefix all error #defines with HAL_ (#8780) 2026-04-19 16:12:18 -07:00
Sam Carlberg
b7df267687 [cmd3] Change Command.noRequirements to accept a command implementation (#8783)
This is more ergonomic than `Command.noRequirements().executing(...)`
2026-04-19 15:40:50 -07:00
Sam Carlberg
3eaeac6150 [developerRobot] Add commands v3 (#8784) 2026-04-19 15:40:08 -07:00
Thad House
ab2aef2c29 [wpilib] Split DriverStation into smaller classes (#8628) 2026-04-18 19:56:45 -07:00
Tyler Veness
58ad633ae2 [build] Fix CMake add_source_jar() OUTPUT_DIR warnings (#8778)
```
CMake Warning (dev) at /usr/share/cmake/Modules/UseJava.cmake:716 (cmake_parse_arguments):
  The OUTPUT_DIR keyword was followed by an empty string or no value at all.
  Policy CMP0174 is not set, so cmake_parse_arguments() will unset the
  _add_jar_OUTPUT_DIR variable rather than setting it to an empty string.
Call Stack (most recent call first):
  cmake/modules/CreateSourceJar.cmake:29:EVAL:1 (add_jar)
  cmake/modules/CreateSourceJar.cmake:29 (cmake_language)
  wpiannotations/CMakeLists.txt:29 (add_source_jar)
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) at /usr/share/cmake/Modules/UseJava.cmake:716 (cmake_parse_arguments):
  The OUTPUT_DIR keyword was followed by an empty string or no value at all.
  Policy CMP0174 is not set, so cmake_parse_arguments() will unset the
  _add_jar_OUTPUT_DIR variable rather than setting it to an empty string.
Call Stack (most recent call first):
  cmake/modules/CreateSourceJar.cmake:29:EVAL:1 (add_jar)
  cmake/modules/CreateSourceJar.cmake:29 (cmake_language)
  wpiunits/CMakeLists.txt:25 (add_source_jar)
This warning is for project developers.  Use -Wno-dev to suppress it.
```
2026-04-17 21:08:41 -07:00
Peter Johnson
a97214df43 [hal] Resource classes: Use expected, refactor errors (#8768)
Also revamp SetLastError et al; Instead of taking status by pointer,
take by value and return new status instead. Rename from SetLast to Make
to make this new usage obvious.

Also move declarations for the error functions from duplicated in the
per-target HALInternal.hpp to a common ErrorHandling.hpp.
2026-04-17 20:19:38 -07:00
Thad House
6cb6903780 [hal,wpilib] Remove a ton of things related to the FPGA (#7846)
Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com>
2026-04-17 19:38:25 -07:00
crueter
fdb454a6b1 [fields] refactor: FTC/FRC separation, better naming scheme (#8034)
Closes #8018

- Adds the 2024-2025 and 2025-2026 FTC field image data
- Used a better naming scheme of `<year> F{R,T}C <gamename>`
  * Also removed generic `field` verbiage from PNG file names
- JSON and PNG files moved into respective `frc` and `ftc` directories
- Rotated fields for the new red-left scheme

Signed-off-by: crueter <swurl@swurl.xyz>
2026-04-17 19:36:38 -07:00
Gold856
056d7bcbbe [wpimath] Make swerve and differential kinematics functions immutable (#8274)
Originally started with just swerve, but expanded to diff and mecanum
(docs only) for parity across the drivetrains. Return value checks are
applied when possible to make migration easier and to error loudly if
people forget.

---------

Co-authored-by: Joseph Eng <91924258+KangarooKoala@users.noreply.github.com>
2026-04-16 21:23:32 -07:00
Thad House
8c80cdcf28 [hal] Add CAN Bus Map (#8765)
We will want a better API for higher level devices that expect to be on
motioncore, but for ones that are not expected to be, it'll be really
nice to have an API that can let us map the motioncore can bus to its
HAL index.
2026-04-16 21:03:39 -07:00
Sam Carlberg
628ba1458f [build] Java 25 support (#8775)
Commands v3 had a few changes due to the upgrade:
- Java 24 removed the Pinned: MONITOR IllegalStateException when
yielding in a synchronized block, so we no longer need to special case
for it
- Lambda method name generation was tweaked, requiring tests to be
updated
- Bazel java_rules needed to be bumped to support Java 25

Closes #8425
2026-04-16 21:02:17 -07:00
Gold856
f96ded6909 Fix various typos (#8769) 2026-04-13 21:51:36 -07:00
sciencewhiz
613c86d1d7 [cmd2] Flatten wpi::cmd::cmd to wpi::cmd (#8764)
Fixes #8763
2026-04-13 21:48:13 -07:00
Tyler Veness
f89cf297e4 [wpical] Fix linker errors (#8766)
```
mold: error: undefined symbol: wpi::fields::GetFields()
>>> referenced by Field2D.cpp
>>>               /home/tav/frc/wpilib/allwpilib/glass/build/libs/glass/static/linuxx86-64/debug/libglassd.a(Field2D.o):((anonymous namespace)::FieldInfo::DisplaySettings())
>>> referenced by Field2D.cpp
>>>               /home/tav/frc/wpilib/allwpilib/glass/build/libs/glass/static/linuxx86-64/debug/libglassd.a(Field2D.o):((anonymous namespace)::FieldInfo::LoadImage())
collect2: error: ld returned 1 exit status
```
The issue seems to stem from libglass linking to the shared version of
fields, whereas wpical requires static linkage.
2026-04-12 22:04:24 -07:00
Tyler Veness
7af3ac579b [build] Upgrade Gradle wrapper and plugins (#8767)
This fixes builds on JDK 26 for me.
2026-04-12 22:03:50 -07:00
Peter Johnson
476b9641c1 [upstream_utils] Update imgui and implot (#8762)
Not updating GLFW yet due to a likely future move to SDL.
2026-04-12 12:19:32 -07:00
Peter Johnson
d76486d885 [upstream_utils] Update googletest to HEAD (#8755)
Co-authored-by: Tyler Veness <calcmogul@gmail.com>
2026-04-11 16:53:55 -07:00
Tyler Veness
7e9138f8c1 [upstream_utils] Upgrade to Google Benchmark 1.9.5 (#8760) 2026-04-11 16:52:24 -07:00
Tricks1228
042567d0ba [wpimath] Prevent CoordinateSystem from accepting left-handed systems (#8750) 2026-04-11 13:53:36 -07:00
PJ Reiniger
c6f54e963c [build] Fixup maven publishing (#8753)
This primarily fixes up the bazel publishing to match the gradle
publishing again, as some new libraries were added but not hooked up to
the maven publishing.

During the process, I noticed that the 3rd party libraries (googletest,
catch2, and imgui_suite) were still getting published on the old
`edu.wpi` namespace. I tried to clean up all the other references to
that that I could. Note: opencv and libssh are handled outside
`allwpilib` so they need to be updated separately.
2026-04-11 13:52:43 -07:00
Alan Everett
9ea63c7fd6 [wpilibc] Return empty string instead of null for GetOpMode (#8754)
Clang 21 catches returning `0` from `GetOpMode` as returning `null`.
Since this state is very momentary and all comparisons inside WPILib are
done against `GetOpModeId` instead, I changed it to return an empty
string.
2026-04-11 13:51:58 -07:00
Tyler Veness
8e72d17770 [upstream_utils] Upgrade to Catch2 3.14.0 (#8757) 2026-04-11 13:51:34 -07:00
Gold856
2102a543d1 Change Java JSON to Avaje Jsonb (#8721)
Jackson is a very heavy library; it supports loads of features that we
don't need, and historically has caused issues due to long class loading
times (a little over 2 seconds to load AprilTagFieldLayout). This often
manifests as a help request in the form of "my robot disables when I do
X, but doesn't disable when doing X in subsequent attempts until code
restart." While SC has brought down Jackson loading times significantly,
with AprilTagFieldLayout loads taking only 330 milliseconds, that's
still a rather long delay, and while libraries should handle any JSON
loading ahead of time to prevent delays in auto/teleop, it would still
be good to make the worst case better to reduce user frustration.
Benchmarks indicate using [Avaje
Jsonb](https://github.com/avaje/avaje-jsonb) to load AprilTagFieldLayout
only takes ~70 ms, a fair chunk of which isn't actually in Avaje Jsonb
(~4 ms is spent on using getResourceAsStream to retrieve the JSON file,
~8 ms is spent on just loading the AprilTag class and its dependencies).

Note that all times listed are end-to-end, meaning nothing else was done
except for the operation being benchmarked, and doing arithmetic on them
can be flawed due to some classes being loaded twice, i.e.,
getResourceAsStream and `new AprilTag()` likely load some of the same
JDK classes and so subtracting both from the Avaje Jsonb load time is
likely slightly incorrect because class loading is being double counted.
For our purposes, it's likely accurate enough and is mostly just for
contextualization.

Benchmarks were run on a Raspberry Pi CM5 with 2 GB of RAM. Source code
for the
[results](https://github.com/user-attachments/files/26471452/benchmark.txt)
can be found in the "Fastjson2" commit
(2456d15ca8ebd17635e607cd40bf8816e77869a1).

Avaje Jsonb uses code generation via annotation processors to generate
the classes needed to do JSON serde and uses service providers to find
them, which will require downstream changes in robot projects, as the
different service providers in each library must be merged together for
Avaje Jsonb to function. We will use the Gradle shadow plugin, as its
already used by the installer and therefore adds zero additional
dependencies.
2026-04-10 23:21:00 -07:00
Thad House
346cd9ed9c [build] Update native utils to fix new mac builds (#8752) 2026-04-10 21:12:18 -07:00
Tyler Veness
aedff82286 [ci] Escape upload-artifact path (#8748)
Asterisk prefixes are interpretted as YAML aliases, which resulted in a
parsing failure.
2026-04-10 17:11:48 -07:00
Joseph Eng
d8df358e6a [cmd3] Update Scheduler class doc description of run() (NFC) (#8747)
#8705 updated the `run()` doc comment but missed the class doc comment.
2026-04-10 16:14:54 -07:00
Zach Harel
a8c7f3e3c6 [wpilib] Change opmodes to purely periodic (#8652)
1. Make the OpMode interface itself periodic; this means the only
differences between `OpMode` and `PeriodicOpMode` are the latter's
methods to add sideloaded periodic callbacks
2. Make OpModeRobot process callbacks in a similar fashion to TimedRobot
and
3. Add some lifecycle functions (discussed below)
4. Pull the callback priority queue from TimedRobot to a new class
called `PeriodicPriorityQueue` so that `TimedRobot` and `OpModeRobot`
have less duplication
5. Fix a typo in the DriverStationJNI class that causes a memory leak
when certain driver station sim calls
6. Port the C++ OpModeRobot tests to Java 

`OpModeRobot` now possesses some `IterativeRobotBase`-stye lifecycle
functions; these functions
1. `robotPeriodic` 
2. `simulationInit` and `simulationPeriodic` 
3. `disabledInit`, `disabledPeriodic`, and `disabledExit`
(note that `simulationInit` and `disabledInit` may be renamed to match
wpilibsuite#8719)

`OpModeRobot` also now processes `OpMode` changes (by the Driver
Station) in its `loopFunc` method, similar to
`IterativeRobotBase.loopFunc` processing game mode changes; `loopFunc`
is, similarly to `TimedRobot`, provided as a default `Callback`

---------

Signed-off-by: Zach Harel <zach@zharel.me>
Co-authored-by: Joseph Eng <91924258+KangarooKoala@users.noreply.github.com>
2026-04-10 13:40:17 -07:00
Peter Johnson
84295180cd [wpinet] WebSocket: Mutex-protect static random device/engine (#8741) 2026-04-10 13:32:55 -07:00
Peter Johnson
bc984234e9 [cmd2] CommandScheduler::Cancel(): Don't mutate in for loop (#8743)
Erasing elements from a container while iterating over the container may
not be well-defined.
2026-04-10 12:30:00 -07:00
Peter Johnson
ea06f0b257 [wpilibj] Watchdog: handle callback throwing an exception (#8742)
Ensure mutex is re-locked.
2026-04-10 12:29:38 -07:00
Peter Johnson
3728bc3b5c [wpilibc] Notifier: Use atomic exchange in move constructor/assignment (#8740) 2026-04-10 12:28:54 -07:00
Peter Johnson
1671150521 [wpiutil] WPI_WaitForObjectTimeout: Add null check (#8739) 2026-04-10 12:28:34 -07:00
Peter Johnson
b7fe3dad46 [ntcore] WireDecodeBinary: Fix some mpack paths (#8738) 2026-04-10 12:28:17 -07:00
Peter Johnson
7e86c10a28 [wpiutil] Fix Semaphore backing vector usage (#8737)
The wrong backing vector was being used (eventIds).
2026-04-10 12:27:52 -07:00
Sam Freund
21f6bdbc1a [hal,wpilib] Remove alert level aliases (#8744) 2026-04-10 12:26:52 -07:00
Sam Freund
ce77e6022f [ci] Remove archival for lint patches (#8745)
When downloading a patch to fix linting errors, it's annoying to have to
unzip it, particularly when it's a single file. This PR updates the
`upload-artifact` action to v7, which allows for uploading an artifact
without zipping it. It also sets archive to false for all patches
generated by linting.
2026-04-10 12:26:13 -07:00
Tyler Veness
b6849a8da3 [wpilib] Rename MotorController setDutyCycle() to setThrottle() (#8720)
Fixes #8716.
2026-04-09 22:28:01 -07:00
Peter Johnson
a4e035ba64 Replace gmtime/localtime with std::chrono (#8735)
Fixes #8734.
2026-04-09 22:25:46 -07:00
Sam Freund
ece8001b1e [wpilib] Add AlertSim function to get only active alerts (#8732) 2026-04-09 22:25:26 -07:00
Sam Carlberg
02c6030251 [cmd3] Enforce command lifetimes across all opmode and command scopes (#8705)
Commands are no longer able to outlive their schedule-site's scope,
regardless of how they were scheduled (set as a default command, bound
to a trigger, or manually scheduled)

As a consequence, default commands need better tracking so the default
command setting can be released when their scope exits and the next-most
appropriate default command can be rescheduled (eg, an opmode sets a
default command, then the globally-scoped default is restored when the
opmode exits). Some complexity is required here to make it work well for
edge cases.

Like `schedule()`, `setDefaultCommand()` will immediately start the new
default command if called inside of another command to avoid 1-loop
delays. However, this does not apply when called by the _current_
default command, as it would result in attempting to cancel the default
command while it's mounted (which is impossible and would throw an
exception)

```java
class Robot extends OpModeRobot {
  final Drive drive = new Drive();
  final CommandXboxController controller = new CommandXboxController(1);

  public Robot() {
    // global default command, active unless overridden in an opmode or command
    drive.setDefaultCommand(drive.stop());

    // global trigger binding, always active
    controller.rightBumper().onTrue(drive.setX());
  }
}

@Teleop
class ExampleOpMode extends PeriodicOpMode {
  public ExampleOpMode(Robot robot) {
    // opmode-specific default command
    robot.drive.setDefaultCommand(robot.drive.operatorControl(robot.controller));

    // opmode-specific binding
    robot.controller.leftBumper().whileTrue(robot.drive.stop());

    // opmode-specific binding that takes precedence over the global binding
    // because it happens last; it "wins out" over the `setX()` binding
    robot.controller.rightBumper().onTrue(robot.drive.selfTest());
  }

  @Override
  public void periodic() {
    Scheduler.getDefault().run();
  }
}
```
2026-04-09 17:05:42 -07:00
Tyler Veness
5a96685c86 [upstream_utils] Upgrade to Sleipnir 0.5.2
This fixes a bug in Sleipnir's Newton solver (the exit status was inaccurate because unconstrained optimization problems can't be infeasible).
2026-04-09 17:03:57 -07:00
Peter Johnson
9ca93fa190 Update for jart/json.cpp change 2026-04-08 08:28:28 -07:00
Peter Johnson
de3e211fdb [upstream_utils] Add jart/json.cpp 2026-04-08 08:28:28 -07:00
Peter Johnson
bfea2b7e1f [upstream_utils] Remove nlohmann JSON 2026-04-08 08:28:28 -07:00
Peter Johnson
3ac168f9d2 [upstream_utils] Add double-conversion to wpiutil 2026-04-08 08:28:28 -07:00
David Vo
44dcf9a3ca [wpilibc] Fix HSV to RGB conversion off-by-one error (#8722)
`Color::FromHSV` didn't match the Java `Color.fromHSV` in some saturated
edge cases, introducing an off-by-one error when the HSV color should
correspond complete saturation of one or two of the primary colors.

Example:

- Java: `Color.fromHSV(0, 255, 255) -> (255, 0, 0)`
- C++: `Color::FromHSV(0, 255, 255) -> (255, 1, 1)`

This also means the following methods are also transitively affected:

- `AddressableLED::LEDData::SetHSV`
- `LEDPattern::Rainbow`

This off-by-one error is introduced by a rounding error from the chroma
calculation, which was dividing by 256 rather than the appropriate
maximum value of 255 like in Java:


7ca35e5678/wpilibj/src/main/java/edu/wpi/first/wpilibj/util/Color.java (L176-L177)

Also port appropriate tests from Java to C++ to catch this bug.

I found this bug when I tried to port `AddressableLEDBuffer` to RobotPy.
Codex found the root cause :)
2026-04-08 08:18:12 -07:00
Tyler Veness
5b4769ea0a [upstream_utils] Upgrade to Sleipnir 0.5.1 (#8726)
There's changes to the diagnostic output and a performance improvement
for autodiff setup. I also updated Java's Options docs to more closely
match upstream.
2026-04-07 23:52:30 -07:00
Tyler Veness
719e9dddc0 [javac] Fix javadoc warnings (#8718)
```
> Task :javacPlugin:javadoc
/home/tav/frc/wpilib/allwpilib/javacPlugin/src/main/java/org/wpilib/javacplugin/OpModeAnnotationValidator.java:31: warning: invalid input: '<'
 *   <li>Name must be <= 32 characters
                      ^
/home/tav/frc/wpilib/allwpilib/javacPlugin/src/main/java/org/wpilib/javacplugin/OpModeAnnotationValidator.java:32: warning: invalid input: '<'
 *   <li>Group must be <= 12 characters
                       ^
/home/tav/frc/wpilib/allwpilib/javacPlugin/src/main/java/org/wpilib/javacplugin/OpModeAnnotationValidator.java:33: warning: invalid input: '<'
 *   <li>Description must be <= 64 characters
                             ^
3 warnings
```

These weren't caught by the `docs:generateJavaDocs` task because the
javacPlugin docs aren't included there.
2026-04-06 09:51:11 -06:00
Thad House
e4ef8a2515 [wpilib] Wait for expansion hub connected for up to half a second during boot (#8715)
Closes #8714
2026-04-06 09:50:47 -06:00
Tyler Veness
173ecd3d02 [hal] Refactor threads API (#8701)
Since sched_setscheduler() requires non-RT priorities to be 0, we can
use that as a sentinel value for disabling RT and condense the Java API
to just two functions with fewer parameters. The thread priority setter
is deprecated since only experts should use it.

The HAL Notifier thread priority setter was replaced with setting the
priority in the thread itself.

The C++ Notifier non-RT and RT constructors were deduplicated.

The real-time scheduler was changed from SCHED_FIFO to SCHED_RR, which
is SCHED_FIFO with threads allowed to run for a maximum time quantum
before yielding (100 ms by default).
2026-04-06 09:49:43 -06:00
David Vo
cc56c42d4c [ci] Avoid duplicate Windows debug build Bazel actions (#8723)
Each Bazel Windows CI job is currently redundantly evaluating the build
actions for both the `opt` and `dbg` compilation modes.

If we group the debug artifact builds together (instead of grouping by
the shared/static library artifacts), the `dbg` compilation mode actions
no longer need to be executed across multiple CI jobs in the matrix.

(Yes, the CI jobs are sharing the Bazel cache, but there's still
overhead in checking the action cache for each action. It's also
possible that two jobs will race to execute the same action.)

| Total actions per job      | [Before] | After |
|----------------------------|---------:|------:|
| Windows x86-64             |    12277 | 10179 |
| Windows x86-64 Static      |    11947 | n/a   |
| Windows x86-64 Debug       |   n/a    |  9895 |
| Windows ARM64              |     5518 |  3420 |
| Windows ARM64 Static       |     5304 | n/a   |
| Windows ARM64 Debug        |   n/a    |  3272 |
| Windows System Core        |     4836 |  2916 |
| Windows System Core Static |     4576 | n/a   |
| Windows System Core Debug  |   n/a    |  2916 |

[Before]:
https://github.com/wpilibsuite/allwpilib/actions/runs/23781230818

This should hopefully translate to shorter wall-clock time Windows CI
jobs.
2026-04-06 09:47:13 -06:00
Thad House
dfc8098b9c [wpiutil] Switch PackCallback to take a range (#8709)
This way it no longer needs something that is contiguous
2026-03-30 21:58:15 -07:00
Thad House
bf218113db [wpiutil] Rename CreateEvent and CreateSemaphore to Make (#8710)
CreateEvent and CreateSemaphore are macros in Windows.h, which causes a
ton of trouble. Just rename the functions.

Closes #7303

Replaces #7336
2026-03-30 15:54:42 -07:00
Tyler Veness
d248c040bf [wpimath] Add Sleipnir Java bindings (#8236)
The wrapper includes reverse mode autodiff, the Problem DSL, and the
optimal control problem API. I wrote it by directly translating the
upstream
[API](https://github.com/SleipnirGroup/Sleipnir/tree/main/include/sleipnir)
and [tests](https://github.com/SleipnirGroup/Sleipnir/tree/main/test) to
Java (i.e., copy-paste-modify).

I replaced the ArmFeedforward and Ellipse2d JNIs with implementations
using the Sleipnir Java bindings. Switching dev binary JNIs to release
by default sped up wpimath test runs from several minutes to 7 seconds.
2026-03-29 22:34:21 -07:00
Thad House
3e821b9448 [hal] Add low level support for Motioncore CAN buses (#8707)
This way vendors can easily access them.
2026-03-29 20:42:25 -07:00
Matt Morley
db42c6cbba [wpinet] Add mDNS discovery tests and fix mDNS JNI bugs (#8682)
In https://github.com/wpilibsuite/allwpilib/issues/8681 we discovered
that multicast service types need to be valid (end with _tcp or _udp),
or else errors are silently swallowed. Let's make our C++ unit test use
a valid name and also check that it works. I think if we
should/shouldn't do this is up for debate still.

I also discovered two bugs in the JNI code that lead to incorrect
results being returned
- Return array index was always 0
- Use of JLocal for the return value seems to mean that the array will
always be NULL in java
2026-03-29 20:41:32 -07:00
sciencewhiz
ceb712b089 [docs] Change NewCommands to Commands v2 (NFC) (#8702) 2026-03-29 20:40:36 -07:00
Thad House
d74644283b [wpilibc] Fix GetUsbId on ExpansionHub in C++ (#8704) 2026-03-29 20:40:06 -07:00
Tyler Veness
f3757bdeae [upstream_utils] Upgrade to Sleipnir 0.5.0 (#8711) 2026-03-29 20:39:18 -07:00
Thad House
962168acf1 [wpinet] Fix port having incorrect endian on windows resolver
For some reason, ip is in network order, but port is in host order.
2026-03-29 16:26:18 -07:00
Peter Johnson
dc4a8d572d [wpilibc] Fix DriverStation comment (NFC) 2026-03-21 00:37:28 -07:00
Peter Johnson
1925cf0e1f [wpilib] Rename LEDPattern constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
d05d3b1c78 [wpilib] Remove PWM.Period enum
Replace it with just numeric values.
2026-03-21 00:37:28 -07:00
Peter Johnson
f2929af00f [wpilib] Rename ADXL345_I2C constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
ea32c247db [wpilib] Rename PneumaticsModuleType constants 2026-03-21 00:37:28 -07:00
Peter Johnson
f060c98992 [wpilib] Rename drivetrain sim enums to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
a57d658ef1 [wpilib] Rename GenericHID and Gamepad enums to all caps
GenericHID.getSupportedOutputs(): Return EnumSet
Gamepad: Add Button-taking accessors
2026-03-21 00:37:28 -07:00
Peter Johnson
d86a745328 [wpilib] Rename DoubleSolenoid.Value constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
c5738fcbad [wpilib] Rename AddressableLED.ColorOrder constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
87e677d4af [wpilib] Rename MotorSafety constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
3776f8a1ef [wpilib] Rename OnboardIMU constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
e73e2e99f7 [wpilibj] SerialPort: update comments to track rename (NFC) 2026-03-21 00:37:28 -07:00
Peter Johnson
49065aa07f [wpilib] Rename CAN constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
38b9214e38 [wpilib] Rename PeriodicOpMode constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
09be21c319 [wpilib] Rename TimedRobot constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
48868020a9 [wpilib] Rename RobotDriveBase constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
7815248d62 [wpilib] Rename MotorType constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
6559d78658 [wpilib] Rename SysIdRoutineLog constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
8fa6976cb2 [wpilib] Rename EdgeConfiguration constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
5ec92df137 [wpilibj] Rename SensorUtil constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
8a802fd670 [wpilib] Rename private constants to all caps 2026-03-21 00:37:28 -07:00
Peter Johnson
b7122f0fda [hal] Rename HAL_kInvalidHandle to HAL_INVALID_HANDLE (#8698) 2026-03-21 00:34:46 -07:00
Peter Johnson
4e4ad9c498 [wpinet] Rename constants to all caps (#8696) 2026-03-20 23:02:21 -07:00
Gold856
0fc1f45324 [wpical] Remove tag ID limit (#8697)
It's annoying to have to update this, and we forgot for 2026.
2026-03-20 20:31:11 -07:00
Gold856
dba033eaee [hal] Clean up references to removed HAL features (#8695)
#7695, #7696, #7697, #7701, #7724, #7753, #7861 removed various features
from the HAL, but forgot to clean up the handles, the WS API, or both.
Additionally, since AnalogInput is the only remaining analog I/O,
AnalogJNI was renamed to the more specific AnalogInputJNI.
2026-03-20 16:50:02 -07:00
Gold856
f1aa84aecf [hal,wpilib] Remove MXP mentions in API docs (NFC) (#8694) 2026-03-20 16:48:53 -07:00
Thad House
fb4bcefabc [wpilibj] Allow passing DS Instance to Robot and OpModes (#8626)
Some discussion with the tech team showed that there were some real
advantages to being able to pass a 2nd type. It allows separating the DS
and Robot. Additionally, we can make the DriverStationBase class
actually usable instead of the existing DriverStation class which is
impossible to handle in intellisense because it has too much.

This won't fully be doable in C++, but we will need to implement
something similar in python.
2026-03-20 14:05:48 -06:00
Peter Johnson
b86204bf45 [wpiutil] Update Color.RGBChannel enum to all caps 2026-03-20 13:24:22 -06:00
Peter Johnson
410c11994e [wpiutil] Update MappedFileRegion MapMode enum to all caps 2026-03-20 13:24:22 -06:00
Peter Johnson
c5e32652f9 [wpiutil] Rename WPI_kInvalidFile to WPI_INVALID_FILE 2026-03-20 13:24:22 -06:00
Peter Johnson
4059797635 [hal,ntcore,cscore] Update Handle constants to all caps 2026-03-20 13:24:22 -06:00
Peter Johnson
aa88fa0fcf [wpiutil] Rename struct constants to all caps 2026-03-20 13:24:22 -06:00
Peter Johnson
c913b27a27 [wpiutil] Rename TimestampSource constants to all caps 2026-03-20 13:24:22 -06:00
Peter Johnson
9ce9918763 [wpiutil] Rename PixelFormat constants to all caps 2026-03-20 13:24:22 -06:00
Peter Johnson
e5107e7e00 [wpiutil] Rename Color constants to all caps 2026-03-20 13:24:22 -06:00
Joseph Eng
8af6bd354e [ntcore] Fix up constants renames (#8693)
Takes care of a few renames missed in #8676.
2026-03-19 23:35:59 -07:00
Peter Johnson
0665aed66b [hal] Fix Python CAN API types prefix (#8687) 2026-03-16 21:47:58 -07:00
Gold856
e81d47fb46 [hal,wpilib] Remove unused error/warning codes (#8684) 2026-03-16 20:26:43 -07:00
Peter Johnson
58e112480a [ntcore] Prefix log levels to avoid macro conflicts (#8686) 2026-03-16 20:24:23 -07:00
Peter Johnson
aad08b9ad1 [hal] Rename SimDevice constants to all caps
Also use enum class for SimDevice C++ wrapper.
2026-03-15 22:38:09 -07:00
Peter Johnson
70f77a1f8e [hal,wpilib] Rename SerialPort constants to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
68ca74c129 [hal,wpilib] Rename REVPH compressor constants to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
c18f811ea7 [hal,wpilib] Rename PowerDistribution constants to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
261a0ebbd7 [hal,wpilib] Rename I2C constants to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
b68fbb1adc [hal,wpilib] Rename Encoder constants to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
f6fdae3212 [hal,wpilib] Rename RuntimeType constants to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
227f01f3bd [hal,wpilib] Rename DriverStation constants to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
614eb1db18 [hal,wpilib] Rename CAN device and manufacturer types to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
fc3be46e6c [hal] Rename kAddressableLEDLength to all caps 2026-03-15 22:38:09 -07:00
Peter Johnson
ab7e4766f6 [ntcore] Rename constants to all caps style (#8676) 2026-03-15 20:44:45 -07:00
Tyler Veness
86dd3ca2b7 [hal] Simplify monotonic_clock (#8678)
The epoch() function, zero() function, and min_time member are all not
part of the std::chrono clock interface.

The default constructor of time_point is
[documented](https://en.cppreference.com/w/cpp/chrono/time_point/time_point.html)
to initialize to the clock's epoch.
2026-03-15 20:42:52 -07:00
Tyler Veness
14e2c1c4cf [ci] Fix all warnings from clang-tidy 22 (#8680)
I ran the following locally:
```bash
gradle generateCompileCommands
./.github/workflows/fix_compile_commands.py build/TargetedCompileCommands/linuxx86-64release/compile_commands.json
wpiformat -default-branch 2027 -no-format -tidy-all -compile-commands=build/TargetedCompileCommands/linuxx86-64release
```

The `HeaderFilterRegex` option is used to filter out warnings from
thirdparty headers.
2026-03-15 20:42:35 -07:00
Peter Johnson
e944ae9aca [hal,wpilib] Rename FPGA clock to monotonic clock (#8672)
- Remove status return from HAL level (clock getting should never fail)
- Remove 32-bit timestamp expand function
- Make monotonic_clock.hpp (formerly fpga_clock.hpp) header-only and
move to root hal include directory
2026-03-15 15:08:41 -07:00
Joseph Eng
1a5b023235 [wpiutil] Add WPI_String usage documentation (NFC) (#8675)
The description is adapted from the PR description in #6299.
2026-03-14 22:38:12 -07:00
Gold856
d1fba06851 Remove deprecated code (#8656) 2026-03-14 21:28:31 -07:00
Gold856
f1adce4cf7 [examples] Clean up examples (#8674)
Move various "examples" into snippets. Several examples that were less
than a full mechanism or robot were moved to snippets. `arcadedrive` and
`tankdrive` were removed in favor of their Gamepad variants. `hidrumble`
was removed due to being too simple. `potentiometerpid` was removed
because of low utility. `gyromecanum` replaced `mecanumdrive` for
deduplication and because very few teams run holonomic drivetrains
without gyros.
2026-03-14 14:13:45 -07:00
Gold856
62ce8944aa [bazel] Add Doxygen excludes for Gradle parity and silencing warnings (#8673) 2026-03-14 09:48:27 -07:00
Thad House
b2b111dc11 Rename FRC to WPILib (#8637) 2026-03-13 23:05:55 -07:00
Peter Johnson
6830c65a15 [hal] Rename HALBase.h to HAL.h (#8668) 2026-03-13 17:19:39 -07:00
Peter Johnson
ab4700854c [hal] Remove HAL.h single header include (#8667) 2026-03-13 15:53:24 -07:00
Peter Johnson
80647654c3 [hal] Add HAL_Status typedef (#8671) 2026-03-13 15:51:43 -07:00
Tyler Veness
907bf05607 [ci] Upgrade to wpiformat 2026.56 (#8666) 2026-03-13 13:15:01 -07:00
2436 changed files with 88234 additions and 69453 deletions

View File

@@ -9,10 +9,10 @@ common --enable_workspace
build --experimental_cc_static_library
build --experimental_cc_shared_library
build --java_language_version=21
build --java_runtime_version=remotejdk_21
build --tool_java_language_version=21
build --tool_java_runtime_version=remotejdk_21
build --java_language_version=25
build --java_runtime_version=remotejdk_25
build --tool_java_language_version=25
build --tool_java_runtime_version=remotejdk_25
test --test_output=errors
test --test_verbose_timeout_warnings
@@ -67,6 +67,7 @@ build:remote_user --config=remote_cache
build:remote_user --config=remote_cache_readonly
build:remote_user --remote_download_toplevel
common:ci --color=yes
build:ci --config=remote_cache
build:ci --remote_download_minimal
build:ci --progress_report_interval=60 --show_progress_rate_limit=60

View File

@@ -72,3 +72,4 @@ CheckOptions:
- key: modernize-use-using.IgnoreExternC
value: 'true'
FormatStyle: file
HeaderFilterRegex: '^((?!thirdparty/).)*$'

View File

@@ -23,14 +23,14 @@ jobs:
- { name: "macOS", classifier: "osxuniversal,osxuniversaldebug,headers,sources,osxuniversalstatic,osxuniversalstaticdebug,linuxsystemcore,linuxsystemcoredebug,linuxsystemcorestatic,linuxsystemcorestaticdebug", os: macOS-15, action: "test" }
- { name: "Windows x86-64", classifier: "windowsx86-64,windowsx86-64debug,headers,sources", os: windows-2022, action: "test" }
- { name: "Windows x86-64 Static", classifier: "windowsx86-64static,windowsx86-64staticdebug", os: windows-2022, action: "test" }
- { name: "Windows x86-64", classifier: "windowsx86-64,windowsx86-64static,headers,sources", os: windows-2022, action: "test" }
- { name: "Windows x86-64 Debug", classifier: "windowsx86-64debug,windowsx86-64staticdebug", os: windows-2022, action: "test" }
- { name: "Windows ARM64", classifier: "windowsarm64,windowsarm64debug", os: windows-2022, action: "build" }
- { name: "Windows ARM64 Static", classifier: "windowsarm64static,windowsarm64staticdebug", os: windows-2022, action: "build" }
- { name: "Windows ARM64", classifier: "windowsarm64,windowsarm64static", os: windows-2022, action: "build" }
- { name: "Windows ARM64 Debug", classifier: "windowsarm64debug,windowsarm64staticdebug", os: windows-2022, action: "build" }
- { name: "Windows System Core", classifier: "linuxsystemcore,linuxsystemcoredebug", os: windows-2022, action: "build" }
- { name: "Windows System Core Static", classifier: "linuxsystemcorestatic,linuxsystemcorestaticdebug", os: windows-2022, action: "build" }
- { name: "Windows System Core", classifier: "linuxsystemcore,linuxsystemcorestatic", os: windows-2022, action: "build" }
- { name: "Windows System Core Debug", classifier: "linuxsystemcoredebug,linuxsystemcorestaticdebug", os: windows-2022, action: "build" }
name: "${{ matrix.action == 'test' && 'Test' || 'Build' }} ${{ matrix.name }}"
runs-on: ${{ matrix.os }}
@@ -73,7 +73,7 @@ jobs:
- name: Install apt dependencies
if: matrix.os == 'ubuntu-24.04'
run: sudo apt-get update && sudo apt-get install -y libgl1-mesa-dev libx11-dev libxcursor-dev libxi-dev libxinerama-dev libxrandr-dev
run: sudo apt-get update && sudo apt-get install -y libgl1-mesa-dev libx11-dev libxcursor-dev libxi-dev libxinerama-dev libxrandr-dev avahi-daemon
- if: matrix.os == 'ubuntu-24.04'
uses: bazel-contrib/setup-bazel@0.15.0
@@ -127,13 +127,42 @@ jobs:
run: git --no-pager diff --exit-code HEAD
- name: Generate diff
run: git diff HEAD > bazel-lint-fixes.patch
run: git diff HEAD > ${{ matrix.platform }}-bazel-lint-fixes.patch
if: ${{ failure() }}
- uses: actions/upload-artifact@v7
with:
archive: false
path: "*-bazel-lint-fixes.patch"
if: ${{ failure() }}
non_robotpy_pregeneration:
name: "Non-RobotPy Pregen"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with: { fetch-depth: 0 }
- id: Setup_bazel_remote
uses: ./.github/actions/setup-bazel-remote
with:
username: ${{ secrets.BAZEL_CACHE_USERNAME }}
password: ${{ secrets.BAZEL_CACHE_PASSWORD }}
- name: Run Non-RobotPy pregeneration
run: bazel run //:write_pregenerated_files
- name: Check Output
run: git --no-pager diff --exit-code HEAD
- name: Generate diff
run: git diff HEAD > non-robotpy-pregeneration.patch
if: ${{ failure() }}
- uses: actions/upload-artifact@v6
with:
name: ${{ matrix.platform }}-bazel-lint-fixes
path: bazel-lint-fixes.patch
name: non-robotpy-pregeneration-fixes
path: non-robotpy-pregeneration.patch
if: ${{ failure() }}
robotpy_pregeneration:

View File

@@ -36,7 +36,7 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 21
java-version: 25
- name: Install sccache
uses: mozilla-actions/sccache-action@v0.0.9

View File

@@ -37,6 +37,12 @@ jobs:
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv-java ninja-build
- name: Setup avahi-daemon
if: runner.os == 'Linux'
run: |
sudo service dbus start
sudo avahi-daemon -D
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew install opencv ninja

View File

@@ -60,11 +60,15 @@ jobs:
with:
image: ${{ matrix.container }}
options: -v ${{ github.workspace }}:/work -w /work -e ARTIFACTORY_PUBLISH_USERNAME -e ARTIFACTORY_PUBLISH_PASSWORD -e GITHUB_REF -e CI
run: ./gradlew build --build-cache -PbuildServer -PskipJavaFormat ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
# Start avahi-daemon and build
run: |
service dbus start
avahi-daemon -D
./gradlew build --build-cache -PbuildServer -PskipJavaFormat ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
env:
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact-name }}
path: build/allOutputs
@@ -141,7 +145,7 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 21
java-version: 25
architecture: ${{ matrix.architecture }}
- name: Import Developer ID Certificate
uses: wpilibsuite/import-signing-certificate@v3
@@ -171,7 +175,7 @@ jobs:
if: |
matrix.artifact-name == 'macOS' && (github.repository == 'wpilibsuite/allwpilib' &&
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027')))
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact-name }}
path: ${{ matrix.outputs }}
@@ -200,7 +204,7 @@ jobs:
env:
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: Documentation
path: docs/build/outputs
@@ -321,7 +325,7 @@ jobs:
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))
with:
distribution: 'temurin'
java-version: 21
java-version: 25
- name: Combine (2027)
if: |
github.repository == 'wpilibsuite/allwpilib' &&
@@ -340,7 +344,7 @@ jobs:
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
if: |
github.repository == 'wpilibsuite/allwpilib' &&
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))

View File

@@ -36,7 +36,7 @@ jobs:
- name: Install wpiformat
run: |
python -m venv ${{ runner.temp }}/wpiformat
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2025.79
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2026.57
- name: Run
run: ${{ runner.temp }}/wpiformat/bin/wpiformat -default-branch 2027
- name: Check output
@@ -44,9 +44,9 @@ jobs:
- name: Generate diff
run: git diff HEAD > wpiformat-fixes.patch
if: ${{ failure() }}
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: wpiformat fixes
archive: false
path: wpiformat-fixes.patch
if: ${{ failure() }}
- name: Write to job summary
@@ -78,7 +78,7 @@ jobs:
- name: Install wpiformat
run: |
python -m venv ${{ runner.temp }}/wpiformat
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2025.79
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2026.57
- name: Create compile_commands.json
run: |
./gradlew generateCompileCommands -Ptoolchain-optional-roboRio
@@ -111,9 +111,9 @@ jobs:
- name: Generate diff
run: git diff HEAD > javaformat-fixes.patch
if: ${{ failure() }}
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: javaformat fixes
archive: false
path: javaformat-fixes.patch
if: ${{ failure() }}
- name: Write to job summary

View File

@@ -27,8 +27,8 @@ jobs:
- name: Generate diff
run: git diff HEAD > pregenerated-files-fixes.patch
if: ${{ failure() }}
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: pregenerated-files-fixes
archive: false
path: pregenerated-files-fixes.patch
if: ${{ failure() }}

View File

@@ -22,7 +22,7 @@ jobs:
ctest-flags: "-E 'wpilibc'"
- name: tsan
cmake-flags: "-DCMAKE_BUILD_TYPE=Tsan"
ctest-env: "TSAN_OPTIONS=second_deadlock_stack=1"
ctest-env: "TSAN_OPTIONS=second_deadlock_stack=1:suppressions=$GITHUB_WORKSPACE/tsan_suppressions.txt"
ctest-flags: "-E 'cscore|cameraserver'"
- name: ubsan
cmake-flags: "-DCMAKE_BUILD_TYPE=Ubsan"
@@ -33,7 +33,7 @@ jobs:
container: wpilib/roborio-cross-ubuntu:2025-24.04
steps:
- name: Install Dependencies
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv-java clang-18 ninja-build
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv-java clang-18 ninja-build avahi-daemon
- name: Install sccache
uses: mozilla-actions/sccache-action@v0.0.9
@@ -46,6 +46,11 @@ jobs:
SCCACHE_WEBDAV_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
SCCACHE_WEBDAV_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
- name: Setup avahi-daemon
run: |
sudo service dbus start
sudo avahi-daemon -D
- name: build
working-directory: build
run: cmake --build . --parallel $(nproc)

View File

@@ -57,7 +57,7 @@ jobs:
run: ./gradlew build -PbuildServer -PskipJavaFormat ${{ matrix.build-options }}
- name: Check free disk space
run: df .
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact-name }}
path: build/allOutputs
@@ -115,7 +115,7 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 21
java-version: 25
architecture: ${{ matrix.architecture }}
- name: Import Developer ID Certificate
uses: wpilibsuite/import-signing-certificate@v3
@@ -159,7 +159,7 @@ jobs:
- name: Check disk free space (macOS)
run: df -h .
if: matrix.os == 'macOS-15'
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact-name }}
path: ${{ matrix.outputs }}

View File

@@ -42,6 +42,18 @@ jobs:
./argparse_lib.py clone
./argparse_lib.py copy-src
./argparse_lib.py format-patch
- name: Run benchmark.py
run: |
cd upstream_utils
./benchmark.py clone
./benchmark.py copy-src
./benchmark.py format-patch
- name: Run double-conversion.py
run: |
cd upstream_utils
./double-conversion.py clone
./double-conversion.py copy-src
./double-conversion.py format-patch
- name: Run eigen.py
run: |
cd upstream_utils

View File

@@ -1,10 +1,20 @@
load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files")
load("@rules_java//java:java_binary.bzl", "java_binary")
load("@rules_java//java:java_plugin.bzl", "java_plugin")
load("@rules_pkg//:mappings.bzl", "pkg_files")
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
load("//shared/bazel/rules:publishing.bzl", "publish_all")
load("//shared/bazel/rules/robotpy:compatibility_select.bzl", "robotpy_compatibility_select")
java_plugin(
name = "avaje_jsonb_generator",
processor_class = "io.avaje.jsonb.generator.JsonbProcessor",
visibility = ["//visibility:public"],
deps = [
"@maven//:io_avaje_avaje_jsonb_generator",
],
)
exports_files([
"LICENSE.md",
"ThirdPartyNotices.txt",
@@ -75,12 +85,14 @@ publish_all(
"//apriltag:apriltag-java_publish.publish",
"//cameraserver:cameraserver-cpp_publish.publish",
"//cameraserver:cameraserver-java_publish.publish",
"//commandsv2:commandsv2-cpp_publish.publish",
"//commandsv2:commandsv2-java_publish.publish",
"//commandsv3:commandsv3-java_publish.publish",
"//cscore:cscore-cpp_publish.publish",
"//cscore:cscore-java_publish.publish",
"//cscore:cscorejnicvstatic-cpp_publish.publish",
"//datalog:datalog-cpp_publish.publish",
"//datalog:datalog-java_publish.publish",
"//tools/datalogtool:datalogtool_publish.publish",
"//docs:wpilibj_publish.publish",
"//epilogue-processor:processor-java_publish.publish",
"//epilogue-runtime:epilogue-java_publish.publish",
@@ -91,11 +103,10 @@ publish_all(
"//glass:glassnt-cpp_publish.publish",
"//hal:hal-java_publish.publish",
"//hal:wpiHal-cpp_publish.publish",
"//javacPlugin:javacPlugin_publish.publish",
"//ntcore:ntcore-cpp_publish.publish",
"//ntcore:ntcore-java_publish.publish",
"//ntcoreffi:ntcoreffi-cpp_publish.publish",
"//tools/outlineviewer:outlineviewer_publish.publish",
"//tools/processstarter:processstarter_publish.publish",
"//romiVendordep:romiVendordep-cpp_publish.publish",
"//romiVendordep:romiVendordep-java_publish.publish",
"//simulation/halsim_ds_socket:halsim_ds_socket-cpp_publish.publish",
@@ -104,14 +115,16 @@ publish_all(
"//simulation/halsim_ws_core:halsim_ws_core-cpp_publish.publish",
"//simulation/halsim_ws_server:halsim_ws_server-cpp_publish.publish",
"//simulation/halsim_xrp:halsim_xrp-cpp_publish.publish",
"//tools/sysid:sysid_publish.publish",
"//thirdparty/catch2:catch2-cpp_publish.publish",
"//thirdparty/googletest:googletest-cpp_publish.publish",
"//thirdparty/imgui_suite:imguiSuite-cpp_publish.publish",
"//tools/datalogtool:datalogtool_publish.publish",
"//tools/outlineviewer:outlineviewer_publish.publish",
"//tools/processstarter:processstarter_publish.publish",
"//tools/sysid:sysid_publish.publish",
"//tools/wpical:wpical_publish.publish",
"//wpiannotations:wpiannotations_publish.publish",
"//wpigui:wpigui-cpp_publish.publish",
"//commandsv2:commandsv2-cpp_publish.publish",
"//commandsv2:commandsv2-java_publish.publish",
"//commandsv3:commandsv3-java_publish.publish",
"//wpilibc:wpilibc-cpp_publish.publish",
"//wpilibcExamples:commands_publish.publish",
"//wpilibcExamples:examples_publish.publish",

View File

@@ -131,7 +131,7 @@ wpilib_config(OPTIONS WITH_WPIMATH WITH_JAVA REQUIRES WITH_WPIUNITS)
set(include_dest include)
set(java_lib_dest java)
if(WITH_JAVA OR WITH_JAVA_SOURCE)
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked" "-proc:full")
find_package(Java REQUIRED COMPONENTS Development)
if(NOT ANDROID)
find_package(JNI REQUIRED COMPONENTS JVM)
@@ -287,6 +287,10 @@ set(WPIUNITS_DEP_REPLACE_IMPL "find_dependency(wpiunits)")
set(WPIANNOTATIONS_DEP_REPLACE_IMPL "find_dependency(wpiannotations)")
set(WPIUTIL_DEP_REPLACE "find_dependency(wpiutil)")
set(DATALOG_DEP_REPLACE "find_dependency(datalog)")
if(WITH_JAVA)
add_subdirectory(wpiannotations)
endif()
add_subdirectory(wpiutil)
add_subdirectory(datalog)
@@ -307,10 +311,6 @@ if(WITH_WPIMATH)
add_subdirectory(wpimath)
endif()
if(WITH_JAVA)
add_subdirectory(wpiannotations)
endif()
if(WITH_WPIUNITS AND NOT WITH_WPIMATH)
# In case of building wpiunits standalone
set(WPIUNITS_DEP_REPLACE ${WPIUNITS_DEP_REPLACE_IMPL})

View File

@@ -4,6 +4,7 @@ So you want to contribute your changes back to WPILib. Great! We have a few cont
- [General Contribution Rules](#general-contribution-rules)
- [What to Contribute](#what-to-contribute)
- [Design Philosophy](#design-philosophy)
- [Contribution Process](#contribution-process)
- [Coding Guidelines](#coding-guidelines)
- [Submitting Changes](#submitting-changes)
@@ -13,12 +14,11 @@ So you want to contribute your changes back to WPILib. Great! We have a few cont
## General Contribution Rules
- Everything in the library must work for the 4000+ teams that will be using it.
- Everything in the library must work for the 14000+ teams that will be using it.
- We need to be able to maintain submitted changes, even if you are no longer working on the project.
- Tool suite changes must be generally useful to a broad range of teams
- Excluding bug fixes, changes in one language generally need to have corresponding changes in other languages.
- Some features, such the addition of C++23 for WPILibC or Functional Interfaces for WPILibJ, are specific to that version of WPILib only. New language features added to C++ must be wrappable in Python for [RobotPy](https://github.com/robotpy).
- Substantial changes often need to have corresponding LabVIEW changes. To do this, we will work with NI on these large changes.
- Some features, such the addition of C++26 for WPILibC or Functional Interfaces for WPILibJ, are specific to that version of WPILib only. New language features added to C++ must be wrappable in Python for [RobotPy](https://github.com/robotpy).
- Changes should have tests.
- Code should be well documented.
- This involves writing tutorials and/or usage guides for your submitted feature. These articles are then hosted on the [WPILib](https://docs.wpilib.org/) documentation website. See the [frc-docs repository](https://github.com/wpilibsuite/frc-docs) for more information.
@@ -28,14 +28,27 @@ So you want to contribute your changes back to WPILib. Great! We have a few cont
- Bug reports and fixes
- We will generally accept bug fixes without too much question. If they are only implemented for one language, we will implement them for any other necessary languages. Bug reports are also welcome, please submit them to our GitHub issue tracker.
- While we do welcome improvements to the API, there are a few important rules to consider:
- Features must be added to Java (WPILibJ), C++ (WPILibC), with rare exceptions.
- Most of Python (RobotPy) is created by wrapping WPILibC with pybind11 via robotpy-build. However, new features to the command framework should also be submitted to [robotpy-commands-v2](https://github.com/robotpy/robotpy-commands-v2) as the command framework is reimplemented in Python.
- During competition season, we will not merge any new feature additions. We want to ensure that the API is stable during the season to help minimize issues for teams.
- Features must be added to Java (WPILibJ), C++ (WPILibC), and Python with rare exceptions.
- Most of Python (RobotPy) is created by wrapping WPILibC with pybind11 via semiwrap. In general, new user-facing functions or classes should have the proper wrapper configs updated, typically located in a YAML file with the same name as the header. See the [in-repo RobotPy README](./README-RobotPy.md) for more info and how to partially auto-update the configs. However, the command framework is reimplemented in Python, and requires code to be ported instead of being wrapped via semiwrap.
- During competition season, we will not merge any new feature additions or removals. We want to ensure that the API is stable during the season to help minimize issues for teams.
- Ask about large changes before spending a bunch of time on them! See [Contribution Process](#contribution-process) for where to ask.
- Features that make it easier for teams with less experience to be more successful are more likely to be accepted.
- Features in WPILib should be broadly applicable to all teams. Anything that is team specific should not be submitted.
- As a rule, we are happy with the general structure of WPILib. We are not interested in major rewrites of all of WPILib. We are open to talking about ideas, but backwards compatibility is very important for WPILib, so be sure to keep this in mind when proposing major changes.
- Generally speaking, we do not accept code for specific sensors. We have to be able to test the sensor in hardware on the WPILib test bed. Additionally, hardware availability for teams is important. Therefore, as a general rule, the library only directly supports hardware that is in the Kit of Parts. If you are a company interested in getting a sensor into the Kit of Parts, please contact FIRST directly at frcparts@firstinspires.org.
- While the library may contain support for specific sensors, these are typically items contained in the FIRST Robotics Competition Kit of Parts or commonly used hardware identified by FIRST or core WPILib Developers. If you think a certain sensor should be supported in WPILib, you may submit an issue justifying the reasons why it should be supported and approval will be determined by FIRST or core WPILib Developers. If you are a company interested in getting a sensor into the Kit of Parts, please contact FIRST directly at frcparts@firstinspires.org.
## Design Philosophy
WPILib's general design philosophy strays far away from the traditional Object-Oriented Programming architectures dominant in enterprise codebases. The general points to follow for WPILib are as follows:
- Prefer functions and composition over inheritance. Inheritance is rigid and often prevents evolution, as adding or removing methods from an inherited class risks breakage. For similar reasons, functional interfaces (`std::function` in C++) are preferred over actual interfaces.
- Avoid opaque black-boxes of functionality. Classes like RamseteCommand or HolonomicDriveController (both removed in 2027) are good examples of this. While they look like a good abstraction that helps beginners, the black-box nature means they are [difficult to debug](https://github.com/wpilibsuite/allwpilib/issues/3350) and it's impossible to instrument the internals to figure out what's going on, or they are extremely clunky to use compared to composing the individual components (thus defeating the point of abstracting it away; SwerveControllerCommand construction was [a huge pile of opaque arguments glued together](https://github.com/wpilibsuite/allwpilib/blob/v2026.2.2/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervecontrollercommand/RobotContainer.java#L104-L114)). Composition is strongly preferred, with strong documentation and examples describing how to do that composition.
- Error at compile time, not runtime. Despite our best efforts, there will always be people who don't read stack traces (understandable for beginner programmers). Compile time errors show up in builds and in an IDE, which is much easier and faster for people to pinpoint and debug. Use language features to make invalid code impossible to build.
- The Matrix class in Java is an example of this. While clunky due to Java's weak generics system, it enforces correct Matrix dimensions at compile time, with the MatBuilder factory method throwing if the array passed in is the wrong size, which leads to the next point:
- Try to only throw exceptions at code startup, and only for things that are obviously incorrect. Robots shouldn't quit, and it's a real "feels bad" moment when yours does, especially in a match. It's oftentimes better to have a robot continue running when it sees nonsensical state as opposed to outright crashing, since other components are often still functional. If you can't make invalid code a compile time error, throwing at the start of the robot program is the next best solution, but avoid throwing in functions likely to be called throughout a robot's runtime.
- Sometimes the behavior of functions are just incorrect if invalid data is passed in, and throwing is one of the only options. This is a judgement call, but if there are no other options, throwing can be okay.
- An alternative to throwing is logging an error, typically with [the Alerts framework](https://docs.wpilib.org/en/latest/docs/software/telemetry/persistent-alerts.html); this is a good choice for runtime errors. Also see https://github.com/wpilibsuite/allwpilib/issues/6766 for an example of not throwing exceptions, but simply logging an error on invalid data.
- Note that hardware configuration issues such as a sensor not existing isn't necessarily obviously incorrect; it could be that the wrong port was specified, but it could also be unplugged due to external factors. Throwing just because it's unplugged can make for a "feels bad" moment, and should be avoided.
## Contribution Process

View File

@@ -13,7 +13,7 @@ This article contains instructions on building projects using a development buil
Development builds are the per-commit build hosted every time a commit is pushed to the [allwpilib](https://github.com/wpilibsuite/allwpilib/) repository. These builds are then hosted on [artifactory](https://frcmaven.wpi.edu/artifactory/webapp/#/home).
To build a project using a development build, find the build.gradle file and open it. Then, add the following code below the plugin section and replace YEAR with the year of the development version. It is also necessary to use a 2027 GradleRIO version, ie `2027.0.0-alpha-3`
To build a project using a development build, find the build.gradle file and open it. Then, add the following code below the plugin section and replace YEAR with the year of the development version. It is also necessary to use a 2027 GradleRIO version, ie `2027.0.0-alpha-5`
```groovy
wpi.maven.useLocal = false
@@ -27,7 +27,7 @@ Java
```groovy
plugins {
id "java"
id "edu.wpi.first.GradleRIO" version "2027.0.0-alpha-3"
id "org.wpilib.GradleRIO" version "2027.0.0-alpha-5"
}
wpi.maven.useLocal = false
@@ -40,7 +40,7 @@ C++
plugins {
id "cpp"
id "google-test-test-suite"
id "edu.wpi.first.GradleRIO" version "2027.0.0-alpha-3"
id "org.wpilib.GradleRIO" version "2027.0.0-alpha-5"
}
wpi.maven.useLocal = false
@@ -61,11 +61,11 @@ Java
```groovy
plugins {
id "java"
id "edu.wpi.first.GradleRIO" version "2027.0.0-alpha-3"
id "org.wpilib.GradleRIO" version "2027.0.0-alpha-5"
}
wpi.maven.useLocal = false
wpi.maven.useFrcMavenLocalDevelopment = true
wpi.maven.useWpilibMavenLocalDevelopment = true
wpi.versions.wpilibVersion = 'YEAR.424242.+'
```
@@ -74,11 +74,11 @@ C++
plugins {
id "cpp"
id "google-test-test-suite"
id "edu.wpi.first.GradleRIO" version "2027.0.0-alpha-3"
id "org.wpilib.GradleRIO" version "2027.0.0-alpha-5"
}
wpi.maven.useLocal = false
wpi.maven.useFrcMavenLocalDevelopment = true
wpi.maven.useWpilibMavenLocalDevelopment = true
wpi.versions.wpilibVersion = 'YEAR.424242.+'
```

View File

@@ -23,3 +23,6 @@ To maintain consistency with other Python scripts, copy an existing `generate_*.
### (Re)Generating files and committing them
Once your Python script is complete, you can run `python generate_<thing>.py` to generate the files. Once you're finished with your files, commit these files to Git. If you regenerated the files and Git indicates the files have changed, but the diff doesn't show any changes, only the line endings have changed. If you expected changes to the generated code, you didn't correctly make changes. If you didn't expect changes, you can ignore this and discard the changes. Also ensure that you've marked the Python script as executable, since this is necessary for CI workflows to run your scripts. To add your script to the CI workflows, edit [.github/workflows/pregen_all.py](.github/workflows/pregen_all.py), and add your script alongside the rest of the scripts.
#### (Re)Generating QuickBuffers files
Regenerating QuickBuffers files requires the Protocol Buffers compiler (protoc), and the QuickBuffers plugin, which can be found on [their releases page](https://github.com/HebiRobotics/QuickBuffers/releases). Once you have both, you can pass their paths into the generation scripts with `--protoc` and `--quickbuf_plugin` and regenerate the files.

View File

@@ -1,23 +1,23 @@
## Publishing Third Party Dependencies
Currently the 3rd party deps are imgui, opencv, google test, libssh, and apriltaglib
Currently the 3rd party external deps are opencv, libssh, ceres, and gtsam.
For publishing these dependencies, the version needs to be manually updated in the publish.gradle file of their respective repository.
Then, in the azure build for the dependency you want to build for, manually start a pipeline build (As of current, this is the `Run Pipeline` button).
A variable needs to be added called `RUN_AZURE_ARTIFACTORY_RELEASE`, with a value of `true`. Then when the pipeline gets started, the final build outputs will be updated to artifactory.
Then, upload a new tag for the dependency you want to build for, which will automatically start a build.
The CI workflow should set `RUN_AZURE_ARTIFACTORY_RELEASE` to `true` on tagged runs. Then when the pipeline gets started, the final build outputs will be uploaded to artifactory.
To use newer versions of C++ dependencies, in `shared/config.gradle`, update the version related to the specific dependency.
For Java dependencies, there is likely a file related to the specific dependency in the shared folder. Update the version in there.
Note, changing artifact locations (This includes changing the artifact year currently, I have an issue open to change this) requires updating the `native-utils` plugin
Note, changing artifact locations requires updating the `native-utils` plugin; specifically, the `configureDependencies` method in the `WPINativeUtilsExtension` class.
## Publishing allwpilib
allwpilib publishes to the development repo on every push to main. To publish a release build, upload a new tag, and a release will automatically be built and published.
## Publishing desktop tools
Desktop tools publish to the development repo on every push to main. To publish a release build, upload a new tag, and a release will automatically be built and published.
### Adding a new robot code dependency/subproject
If a new subproject has been added that is meant for use from robot code, both GradleRIO and the `native-utils` plugin need to be updated. `native-utils` is updated in the same way as 3rd party dependencies. For GradleRIO, update the `WPIJavaDepsExtension` to contain your new subproject's artifacts.
## Publishing VS Code
Before publishing, make sure to update the gradlerio version in `vscode-wpilib/resources/gradle/version.txt` Also make sure the gradle wrapper version matches the wrapper required by gradlerio.
Before publishing, make sure to update the GradleRIO version in `vscode-wpilib/resources/gradle/version.txt`. Also make sure the Gradle Wrapper version matches the wrapper required by GradleRIO.
Upon pushing a tag, a release will be built, and the files will be uploaded to the releases on GitHub.
## Publishing GradleRIO

View File

@@ -3,6 +3,8 @@ module(
version = "0.0.0",
)
include("//docs:doxygen.MODULE.bazel")
bazel_dep(name = "apple_support", version = "2.0.0", repo_name = "build_bazel_apple_support")
# TODO(austin): Upgrade when the patches land.
@@ -21,7 +23,7 @@ bazel_dep(name = "bazel_features", version = "1.33.0")
bazel_dep(name = "aspect_bazel_lib", version = "2.14.0")
bazel_dep(name = "bazel_skylib", version = "1.8.2")
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "rules_java", version = "8.14.0")
bazel_dep(name = "rules_java", version = "8.16.1")
bazel_dep(name = "rules_python", version = "1.7.0")
bazel_dep(name = "rules_pycross", version = "0.8.1")
@@ -51,12 +53,11 @@ maven.install(
name = "maven",
artifacts = [
"org.ejml:ejml-simple:0.44.0",
"com.fasterxml.jackson.core:jackson-annotations:2.19.2",
"com.fasterxml.jackson.core:jackson-core:2.19.2",
"com.fasterxml.jackson.core:jackson-databind:2.19.2",
"io.avaje:avaje-jsonb:3.11",
"io.avaje:avaje-jsonb-generator:3.11",
"us.hebi.quickbuf:quickbuf-runtime:1.4",
"com.google.code.gson:gson:2.13.1",
"edu.wpi.first.thirdparty.frc2025.opencv:opencv-java:4.10.0-3",
"org.wpilib.thirdparty.opencv:opencv-java:2027-4.13.0-1",
"org.junit.jupiter:junit-jupiter:5.10.1",
"org.junit.platform:junit-platform-console:1.10.1",
"org.junit.platform:junit-platform-launcher:1.10.1",
@@ -77,32 +78,6 @@ maven.install(
use_repo(maven, "maven", "unpinned_maven")
bazel_dep(name = "caseyduquettesc_rules_python_pytest", version = "1.1.1", repo_name = "rules_python_pytest")
bazel_dep(name = "rules_doxygen", version = "2.5.0")
archive_override(
module_name = "rules_doxygen",
integrity = "sha256-qxfKreTkQnV4tUX6KJDFXuOJj4p6VZdBYjAie77I5ho=",
strip_prefix = "rules_doxygen-2.5.0",
urls = ["https://github.com/TendTo/rules_doxygen/releases/download/2.5.0/rules_doxygen-2.5.0.tar.gz"],
)
doxygen_extension = use_extension("@rules_doxygen//:extensions.bzl", "doxygen_extension")
doxygen_extension.configuration(
platform = "windows",
sha256 = "44658b9cc5c91749e6e3cc426ba63e2550b4a4a7619065acd77029aa234719c6",
version = "1.15.0",
)
doxygen_extension.configuration(
platform = "mac",
sha256 = "b7630eaa0d97bb50b0333929ef5dc1c18f9e38faf1e22dca3166189a9718faf0",
version = "1.15.0",
)
doxygen_extension.configuration(
platform = "linux",
sha256 = "0ec2e5b2c3cd82b7106d19cb42d8466450730b8cb7a9e85af712be38bf4523a1",
version = "1.15.0",
)
use_repo(doxygen_extension, "doxygen")
bazel_dep(name = "eigen", version = "5.0.1")
local_path_override(
module_name = "eigen",
@@ -116,29 +91,29 @@ http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_
http_file(
name = "quickbuffer_protoc_linux",
executable = True,
sha256 = "f9a041bccaa7040db523666ef1b5fe9f6f94e70a82c88951f18f58aadd9c50b5",
urls = ["https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/1.3.2/protoc-gen-quickbuf-1.3.2-linux-x86_64.exe"],
sha256 = "02767f5f662720c121dfaaa9109aefa9b0b1e2415cbe1af9e4713a7b00663696",
urls = ["https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/1.3.3/protoc-gen-quickbuf-1.3.3-linux-x86_64.exe"],
)
http_file(
name = "quickbuffer_protoc_osx_x86-64",
executable = True,
sha256 = "ea307c2b69664ae7e7c69db4cddf5803187e5a34bceffd09a21652f0f16044f7",
urls = ["https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/1.3.2/protoc-gen-quickbuf-1.3.2-osx-x86_64.exe"],
sha256 = "cdc0b4b188f944dddd4430bcd6f6266ca1aaf8c33940d7bee1ed63fc962d8525",
urls = ["https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/1.3.3/protoc-gen-quickbuf-1.3.3-osx-x86_64.exe"],
)
http_file(
name = "quickbuffer_protoc_osx_aarch64",
executable = True,
sha256 = "a9abdee09d8b5ef0aa954b238536917313511deec11e1901994af26ade033e28",
urls = ["https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/1.3.2/protoc-gen-quickbuf-1.3.2-osx-aarch_64.exe"],
sha256 = "95fa0a22ad2d9fa8f84a31cf3a0670b18c0ad954f73035f60cfb77c2814fb41c",
urls = ["https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/1.3.3/protoc-gen-quickbuf-1.3.3-osx-aarch_64.exe"],
)
http_file(
name = "quickbuffer_protoc_windows",
executable = True,
sha256 = "27dc1f29764a62b5e6a813a4bcd63e81bbdc3394da760a44acae1025b4a89f1d",
urls = ["https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/1.3.2/protoc-gen-quickbuf-1.3.2-windows-x86_64.exe"],
sha256 = "8a30b2eaebefbedc3b592118670de1ab6ea1aa19dcf8cdab220e25485ccd4a0a",
urls = ["https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/1.3.3/protoc-gen-quickbuf-1.3.3-windows-x86_64.exe"],
)
bazel_dep(name = "rules_bzlmodrio_toolchains", version = "2025-1.bcr6")

11
MODULE.bazel.lock generated
View File

@@ -12,7 +12,8 @@
"https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16",
"https://bcr.bazel.build/modules/abseil-cpp/20250127.1/MODULE.bazel": "c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1",
"https://bcr.bazel.build/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215",
"https://bcr.bazel.build/modules/abseil-cpp/20250512.1/source.json": "d725d73707d01bb46ab3ca59ba408b8e9bd336642ca77a2269d4bfb8bbfd413d",
"https://bcr.bazel.build/modules/abseil-cpp/20250814.0/MODULE.bazel": "c43c16ca2c432566cdb78913964497259903ebe8fb7d9b57b38e9f1425b427b8",
"https://bcr.bazel.build/modules/abseil-cpp/20250814.0/source.json": "b88bff599ceaf0f56c264c749b1606f8485cec3b8c38ba30f88a4df9af142861",
"https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896",
"https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85",
"https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442",
@@ -49,6 +50,7 @@
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
"https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
"https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/source.json": "34a3c8bcf233b835eb74be9d628899bb32999d3e0eadef1947a0a562a2b16ffb",
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
@@ -112,9 +114,11 @@
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
"https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513",
"https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8",
"https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c",
"https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37",
"https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8",
"https://bcr.bazel.build/modules/rules_cc/0.2.14/source.json": "55d0a4587c5592fad350f6e698530f4faf0e7dd15e69d43f8d87e220c78bea54",
"https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642",
"https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
"https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
@@ -129,7 +133,8 @@
"https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2",
"https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe",
"https://bcr.bazel.build/modules/rules_java/8.14.0/MODULE.bazel": "717717ed40cc69994596a45aec6ea78135ea434b8402fb91b009b9151dd65615",
"https://bcr.bazel.build/modules/rules_java/8.14.0/source.json": "8a88c4ca9e8759da53cddc88123880565c520503321e2566b4e33d0287a3d4bc",
"https://bcr.bazel.build/modules/rules_java/8.16.1/MODULE.bazel": "0f20b1cecaa8e52f60a8f071e59a20b4e3b9a67f6c56c802ea256f6face692d3",
"https://bcr.bazel.build/modules/rules_java/8.16.1/source.json": "072f8d11264edc499621be2dc9ea01d6395db5aa6f8799c034ae01a3e857f2e4",
"https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017",
"https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939",
"https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2",
@@ -263,7 +268,7 @@
"repoRuleId": "@@rules_bzlmodrio_toolchains+//toolchains:configure_cross_compiler.bzl%configure_cross_compiler",
"attributes": {
"extra_defines": [
"-D__FRC_SYSTEMCORE__=1"
"-D__FIRST_SYSTEMCORE__=1"
],
"bin_subfolder": "bookworm/bin",
"bin_prefix": "aarch64-bookworm-linux-gnu-",

View File

@@ -18,10 +18,10 @@ The first types are Java artifacts. These are usually published as `jar` files.
Example:
```
edu.wpi.first.wpilibj:wpilibj-java:version
org.wpilib.wpilibj:wpilibj-java:version
```
The second types are native artifacts. These are usually published as `zip` files. The `-sources` and `-headers` classifiers contain the sources and headers respectively for the library. Each artifact also contains a classifier for each platform we publish. This platform is in the format `{os}{arch}`. The full list of supported platforms can be found in [native-utils](https://github.com/wpilibsuite/native-utils/blob/main/src/main/java/edu/wpi/first/nativeutils/WPINativeUtilsExtension.java#L94). If the library is built statically, it will have `static` appended to the classifier. Additionally, if the library was built in debug mode, `debug` will be appended to the classifier. The platform artifact only contains the binaries for a specific platform. Note that the binary artifacts never contain the headers, you always need the `-headers` classifier to get those.
The second types are native artifacts. These are usually published as `zip` files. The `-sources` and `-headers` classifiers contain the sources and headers respectively for the library. Each artifact also contains a classifier for each platform we publish. This platform is in the format `{os}{arch}`. The full list of supported platforms can be found in [native-utils in the Platforms nested class](https://github.com/wpilibsuite/native-utils/blob/main/src/main/java/org/wpilib/nativeutils/WPINativeUtilsExtension.java). If the library is built statically, it will have `static` appended to the classifier. Additionally, if the library was built in debug mode, `debug` will be appended to the classifier. The platform artifact only contains the binaries for a specific platform. Note that the binary artifacts never contain the headers, you always need the `-headers` classifier to get those.
If the library is Java and C++ and has a JNI component, the native artifact will have a shared library containing JNI entrypoints alongside the C++ shared library. This JNI shared library will have a `jni` suffix in the file name.
@@ -29,8 +29,8 @@ Native artifacts are published with the base artifact name as their artifact ID,
Example:
```
edu.wpi.first.wpimath:wpimath-cpp:version:classifier@zip
edu.wpi.first.wpimath:wpimath-cpp:version:windowsx86-64staticdebug@zip
org.wpilib.wpimath:wpimath-cpp:version:classifier@zip
org.wpilib.wpimath:wpimath-cpp:version:windowsx86-64staticdebug@zip
```
## Provided Artifacts
@@ -38,7 +38,7 @@ This repository provides the following artifacts. Below each artifact is its dep
For C++, if building with static dependencies, the listed order should be the link order in your linker.
All artifacts are based at `edu.wpi.first.artifactname` in the repository.
All artifacts are based at `org.wpilib.artifactname` in the repository.
* wpiutil
@@ -52,32 +52,33 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
* wpiutil
* ntcore
* wpiutil
* wpinet
* wpiutil
* glass/libglass
* wpiutil
* wpimath
* wpigui
* wpimath
* wpiutil
* glass/libglassnt
* wpiutil
* wpinet
* ntcore
* wpimath
* wpigui
* ntcore
* wpinet
* wpimath
* wpiutil
* hal
* ntcore
* wpiutil
* halsim
* wpiutil
* wpinet
* libglassnt
* libglass
* ntcore
* wpimath
* wpigui
* libglass
* libglassnt
* wpinet
* wpiutil
* cscore
* opencv
@@ -126,12 +127,16 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
### Third Party Artifacts
This repository provides the builds of the following third party software.
This repository provides the builds of the following third party software:
All artifacts are based at `edu.wpi.first.thirdparty.frcYEAR` in the repository.
* apriltaglib
* googletest
* imgui
* opencv
* libssh
Other software can be found in their corresponding GitHub repositories:
* ceres: https://github.com/wpilibsuite/thirdparty-ceres
* gtsam: https://github.com/wpilibsuite/thirdparty-gtsam
* opencv: https://github.com/wpilibsuite/thirdparty-opencv
* libssh: https://github.com/wpilibsuite/thirdparty-libssh
All artifacts are based at `org.wpilib.thirdparty` in the repository.

View File

@@ -1,10 +1,10 @@
# WPILib Bazel Support
WPILib is normally built with Gradle, but [Bazel](https://www.bazel.build/) can also be used to increase development speed due to the superior caching ability and the ability to use remote caching and remote execution (on select platforms)
WPILib is normally built with Gradle, but [Bazel](https://www.bazel.build/) can also be used to increase development speed due to the superior caching ability and the ability to use remote caching and remote execution (on select platforms).
## Prerequisites
- Install [Bazelisk](https://github.com/bazelbuild/bazelisk/releases) and add it to your path. Bazelisk is a wrapper that will download the correct version of bazel specified in the repository. Note: You can alias/rename the binary to `bazel` if you want to keep the familiar `bazel build` vs `bazelisk build` syntax.
- Install [Bazelisk](https://github.com/bazelbuild/bazelisk/releases) and add it to your path. Bazelisk is a wrapper that will download the correct version of Bazel specified in the repository. Note: You can alias/rename the binary to `bazel` if you want to keep the familiar `bazel build` vs `bazelisk build` syntax.
## Building
To build the entire repository, simply run `bazel build //...`. To run all of the unit tests, run `bazel test //...`
@@ -14,7 +14,7 @@ Other examples:
- `bazel coverage //wpiutil/...` - (*Nix only) - Runs a code coverage report for both C++ and Java on all the targets under wpiutil
## User settings
When invoking bazel, it will check if `user.bazelrc` exists for additional, user specified flags. You can use these settings to do things like always ignore buildin a specific folder, or limiting the CPU/RAM usage during a build.
When invoking Bazel, it will check if `user.bazelrc` exists for additional, user specified flags. You can use these settings to do things like always ignore builds in a specific folder, or limiting the CPU/RAM usage during a build.
Examples:
- `build --build_tag_filters=-wpi-example` - Do not build any targets tagged with `wpi-example` (Currently all of the targets in wpilibcExamples and wpilibjExamples contain this tag)
- `build -c opt` - Always build optimized targets. The default compiler flags were chosen to build as fast as possible, and thus don't contain many optimizations
@@ -36,12 +36,12 @@ Modify this to your likings if you want to build less.
## Pregenerating Files
allwpilib uses extensive use of pre-generating files that are later used to build C++ / Java libraries that are tracked by version control. Quite often,
these pre-generation scripts use some configuration file to create multipile files inside of an output directory. While this process could be accomplished
these pre-generation scripts use some configuration file to create multiple files inside of an output directory. While this process could be accomplished
with a `genrule` that would require an explicit listing of every output file, which would be tedious to maintain as well as potentially confusing to people
adding new features those libraries. Therefor, we use `@aspect_bazel_lib` and their `write_source_files` feature to generate these directories. In the event that the generation process creates more than a small handful of predictable files, a custom rule is written to generate the directory.
adding new features those libraries. Therefore, we use `@aspect_bazel_lib` and their `write_source_files` feature to generate these directories. In the event that the generation process creates more than a small handful of predictable files, a custom rule is written to generate the directory.
## Remote Caching
One of the huge benefits of bazel is its remote caching ability. However, due to bazels strict build definitions it is hard to share remote cache artifacts between different computers unless our toolchains are fully hermetic, which means you are unlikely to be able to reuse the cache artifacts published from the `main` branch on your local machine like you might be able to with the `gradle` or `cmake` caches. Luckily the github actions CI machines are generally stable between runs and can reuse cache artifacts, and your local machine should remain stable, so if you set up a free buildbuddy account you can have your forks CI actions be able to use a personalized cache, as well as your local machine.
One of the huge benefits of Bazel is its remote caching ability. However, due to Bazel's strict build definitions, it is hard to share remote cache artifacts between different computers unless our toolchains are fully hermetic, which means you are unlikely to be able to reuse the cache artifacts published from the `main` branch on your local machine like you might be able to with the `gradle` or `cmake` caches. Luckily, the GitHub Actions CI machines are generally stable between runs and can reuse cache artifacts, and your local machine should remain stable, so if you set up a free buildbuddy account you can have your fork's CI actions be able to use a personalized cache, as well as your local machine.
For the main `allwpilib` upstream, the cache is only updated on the main branch; pull requests from forks will not be able to modify the cache. However, you can set up your fork to enable its own cache by following the steps below.

View File

@@ -5,16 +5,17 @@ WPILib is normally built with Gradle, however for some systems, such as Linux ba
## Libraries that get built
* apriltag
* cameraserver
* commandsv2
* commandsv3
* cscore
* datalog
* fields
* hal (simulation HAL only)
* ntcore
* romiVendordep
* simulation extensions
* wpigui
* wpilib (wpilibc, wpilibj, and myRobot)
* commandsv2
* wpilib (wpilibc, wpilibj, and developerRobot)
* wpimath
* wpinet
* wpiunits
@@ -26,17 +27,16 @@ WPILib is normally built with Gradle, however for some systems, such as Linux ba
* glass
* outlineviewer
* sysid
* wpical
* halsim_gui (if simulation extensions are enabled)
By default, all libraries get built with a default CMake setup. The libraries are built as shared libraries, and include the JNI libraries as well as building the Java JARs. Data Log Tool and the roboRIO Team Number Setter are only built if libssh is available.
By default, all libraries get built with a default CMake setup. The libraries are built as shared libraries, and include the JNI libraries as well as building the Java JARs. Data Log Tool is only built if libssh is available.
## Prerequisites
OpenCV needs to be findable by CMake. On systems like the Jetson, this is installed by default. Otherwise, you will need to build OpenCV from source and install it.
If you want JNI and Java, you will need a JDK of at least version 21 installed. In addition, you need a `JAVA_HOME` environment variable set properly and set to the JDK directory.
If you are building with unit tests or simulation modules, you will also need an Internet connection for the initial setup process, as CMake will clone google-test and imgui from GitHub.
If you want JNI and Java, you will need a JDK of at least version 25 installed. In addition, you need a `JAVA_HOME` environment variable set properly and set to the JDK directory.
## Build Options
@@ -61,7 +61,7 @@ The following build options are available:
* `WITH_TESTS` (ON Default)
* This option will build C++ unit tests. These can be run via `ctest -C <config>`, where `<config>` is the build configuration, e.g. `Debug` or `Release`.
* `WITH_WPILIB` (ON Default)
* This option will build the HAL and wpilibc/j during the build. The HAL is the simulation HAL, unless the external HAL options are used. The CMake build has no capability to build for the roboRIO.
* This option will build the HAL and wpilibc/j during the build. The HAL is the simulation HAL, unless the external HAL options are used. The CMake build has no capability to build for Systemcore.
* `WITH_WPIMATH` (ON Default)
* This option will build the wpimath library. This option must be on to build wpilib.
* `WITH_WPIUNITS` (`WITH_JAVA` Default)
@@ -89,11 +89,11 @@ If you want, you can also use `ccmake` in order to visually set these properties
## Presets
The WPILib CMake setup has a variety of presets for common configurations and options used. The default sets the generator to Ninja and build directory to `build-cmake`. The other presets are `with-java` (sets `WITH_JAVA=ON`), `sccache` (sets the C/C++ compiler launcher to sccache), and `with-java-sccache` (a comibination of `with-java` and `sccache`.
The WPILib CMake setup has a variety of presets for common configurations and options used. The default sets the generator to Ninja and build directory to `build-cmake`. The other presets are `with-java` (sets `WITH_JAVA=ON`), `sccache` (sets the C/C++ compiler launcher to sccache), and `with-java-sccache` (a combination of `with-java` and `sccache`).
## Building
Once you have CMake setup. run `cmake --build .` from the directory you configured CMake in. This will build all libraries possible. We recommend running `cmake --build .` with multiple jobs. For allwpilib, a good rule of thumb is one worker for every 2 GB of available RAM. To run a multiple job build, run the following command with x being the number of jobs you want.
Once you have CMake setup. run `cmake --build .` from the directory you configured CMake in. This will build all libraries possible. We recommend running `cmake --build .` with multiple jobs. For allwpilib, a good rule of thumb is one worker for every 2 GB of available RAM. To run a multi-job build, run the following command with x being the number of jobs you want.
```
cmake --build . --parallel x
@@ -211,10 +211,11 @@ If you are missing Java, you will get a message like the following.
```
CMake Error at /usr/share/cmake-3.5/Modules/FindPackageHandleStandardArgs.cmake:148 (message):
Could NOT find Java (missing: Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE
Java_JAVAC_EXECUTABLE Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE)
Java_JAVAC_EXECUTABLE Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
Development)
```
If this happens, make sure you have a JDK of at least version 8 installed, and that your JAVA_HOME variable is set properly to point to the JDK.
If this happens, make sure you have a JDK of at least version 25 installed, and that your JAVA_HOME variable is set properly to point to the JDK.
In addition, if you do not need Java, you can disable it with `-DWITH_JAVA=OFF`.
@@ -224,7 +225,7 @@ If one of the libraries can't be found, you will get an error similar to this on
```
java.io.IOException: wpiHaljni could not be loaded from path or an embedded resource.
attempted to load for platform /windows/x86-64/
attempted to load for platform windows-x86_64
Last Load Error:
C:\Program Files (x86)\allwpilib\bin\wpiHaljni.dll: Can't find dependent libraries
```

View File

@@ -1,23 +1,22 @@
# robotpy in allwpilb
allwpilib hosts a mirror of RobotPy that can be built with bazel on Linux. The intent of the mirror is to have breaking changes identified early and fixed by the PR creator so that when wpilib releases are made there is much less work required to release a RobotPy version that wraps it. It is not a goal for allwpilib to replace the RobotPy repo; it will still be considered the "source of truth" for python builds and will be responsible for building against all of the applicable architectures and multiple versions of python.
# robotpy in allwpilib
allwpilib hosts a mirror of RobotPy that can be built with Bazel on Linux. The intent of the mirror is to have breaking changes identified early and fixed by the PR creator so that when WPILib releases are made, there is much less work required to release a RobotPy version that wraps it. It is not a goal for allwpilib to replace the RobotPy repo; it will still be considered the "source of truth" for Python builds and will be responsible for building against all of the applicable architectures and multiple versions of Python.
## Build Process
The upstream RobotPy repository uses toml configuration files and semiwrap to produce Meson build scripts. The allwpilib fork uses these toml configuration files to auto generate bazel build scripts. In general, each project (wpiutil, wpimath, etc) defines two pybind extensions; one that simply wraps the native library, and another that adds extension(s) that and contains all of the python files for the library. Both of these subprojects have auto-generated build files; a `robotpy_native_build_info.bzl` for the lidar wraper and `robotpy_pybind_build_info.bzl` which defines the extensions and python library.
The upstream RobotPy repository uses TOML configuration files and semiwrap to produce Meson build scripts. The allwpilib fork uses these TOML configuration files to auto-generate Bazel build scripts. In general, each project (wpiutil, wpimath, etc) defines two pybind extensions; one that simply wraps the native library, and another that adds extension(s) that and contains all of the Python files for the library. Both of these subprojects have auto-generated build files; a `robotpy_native_build_info.bzl` for the native wrapper and `robotpy_pybind_build_info.bzl` which defines the extensions and Python library.
## Disabling robotpy builds
Building the robotpy software on top of the standard C++/Java software can result in more than doubling the amount of time it takes to compile. To skip building the robotpy tooling you can add `--config=skip_robotpy` to the command line or to your `user.bazelrc`
## Disabling RobotPy builds
Building the RobotPy software on top of the standard C++/Java software can result in more than doubling the amount of time it takes to compile. To skip building the RobotPy tooling, you can add `--config=skip_robotpy` to the command line or to your `user.bazelrc`.
# Syncing with robotpy
[Copybara](https://github.com/google/copybara) is used to maintin synchronization between the upstream robotpy repositories and the allwpilib mirror. Github actions can be manually run which will create pull requests that will update all of the robotpy files between the two repositories. The ideal process is that the allwpilib mirror is always building in CI, and once a release is created the RobotPy team can run the `wpilib -> robotpy` copybara task, make any fine tuned adjustements and create their release. In the event that additional changes are made on the robotpy side, they can run the `robotpy -> wpilib` task to push the updates back to the mirror. However the goal of the mirroring the software here is to be able to more rapidly test changes and will hopefully overwhelmingly eliminate the need for syncs this direction.
# Syncing with RobotPy
[Copybara](https://github.com/google/copybara) is used to maintain synchronization between the upstream RobotPy repositories and the allwpilib mirror. GitHub Actions can be manually run, which will create pull requests that will update all of the RobotPy files between the two repositories. The ideal process is that the allwpilib mirror is always building in CI, and once a release is created, the RobotPy team can run the `wpilib -> robotpy` Copybara task, make any fine tuned adjustments and create their release. In the event that additional changes are made on the RobotPy side, they can run the `robotpy -> wpilib` task to push the updates back to the mirror. However, the goal of the mirroring the software here is to be able to more rapidly test changes and will hopefully overwhelmingly eliminate the need for syncs in this direction.
## Creating a user config
The copybara scripts needs to know information about what repositories it will be pushing the sync'd changes. These can be specified on the command line, or you can create a `shared/bazel/copybara/.copybara.json` config file to save your personalized settings to avoid having to type things out every time. To run the full suite of migrations, you need a fork of [allwpilib](https://github.com/wpilibsuite/allwpilib), a fork of [mostrobotpy](https://github.com/robotpy/mostrobotpy), and a fork of robotpy's [commands-v2](https://github.com/robotpy/robotpy-commands-v2). If you only wish to run a subset of commands (i.e. not sync the commands project), you do not need to include that in your user config.
The Copybara scripts needs to know information about what repositories it will be pushing the synced changes to. These can be specified on the command line, or you can create a `shared/bazel/copybara/.copybara.json` config file to save your personalized settings to avoid having to type things out every time. To run the full suite of migrations, you need a fork of [allwpilib](https://github.com/wpilibsuite/allwpilib), a fork of [mostrobotpy](https://github.com/robotpy/mostrobotpy), and a fork of RobotPy's [commands-v2](https://github.com/robotpy/robotpy-commands-v2). If you only wish to run a subset of commands (i.e. not sync the commands project), you do not need to include that in your user config.
Example config:
```
```json
{
"mostrobotpy_local_repo_path": "/home/<username>/git/robotpy/robotpy_monorepo/mostrobotpy",
"mostrobotpy_fork_repo": "https://github.com/<username>/mostrobotpy.git",
"allwpilib_fork_repo": "https://github.com/<username>/allwpilib.git",
"robotpy_commandsv2_fork_repo": "https://github.com/<username>/robotpy-commands-v2.git"
@@ -40,24 +39,24 @@ Example config:
- **Pushing changes to mostrobotpy**:
This process is slightly more complicated, because you will almost certainly also need to update the maven artifacts that mostrobopy is using. Because of this, you must also specify the version number that has been published to wpilibs maven repository. If you are trying to get an early, non-released development build pushed over, you can also add the `--development_build` flag
This process is slightly more complicated, because you will almost certainly also need to update the Maven artifacts that mostrobopy is using. Because of this, you must also specify the version number that has been published to WPILib's Maven repository. If you are trying to get an early, non-released development build pushed over, you can also add the `--development_build` flag:
`python3 shared/bazel/copybara/run_copybara.py allwpilib_to_mostrobotpy --wpilib_bin_version=2027.0.0-alpha-3-86-g418b381 --development_build -y`
# Debugging Build Errors
The build process is highly automated and automatically parses C++ header files to generate pybind11 bindings. Some of these steps here are considered "pregeneration" steps, and the bazel build system will update build files as necessary. If a new header is added, or if the contents of a header file has changed, some of the pregeneration scripts might need to be run. If you encounter an error building `robotpy` code, it is recommended that you go through these steps to make sure everything is set up correctly. The examples are for `wpilibc`, but similar build tasks and tests exist for each wrapped project
The build process is highly automated and automatically parses C++ header files to generate pybind11 bindings. Some of these steps here are considered "pregeneration" steps, and the Bazel build system will update build files as necessary. If a new header is added, or if the contents of a header file has changed, some of the pregeneration scripts might need to be run. If you encounter an error building `robotpy` code, it is recommended that you go through these steps to make sure everything is set up correctly. The examples are for `wpilibc`, but similar build tasks and tests exist for each wrapped project.
## 1. scan-headers
This can be the first source of problems if a new header file has been added. `semiwrap` will look through all of the headers for a library and notify you if a file is not covered by the projects `pyproject.toml` file. Bazel has a test case to ensure the files are up to date.
An example test failure when a new header being introduced. You can run the test with the following command
An example test failure when a new header being introduced. You can run the test with the following command:
bazel run //wpilibc:robotpy-wpilib-scan-headers
```
# wpi
ExpansionHub = "wpi/ExpansionHub.hpp"
ExpansionHubCRServo = "wpi/ExpansionHubCRServo.hpp"
ExpansionHubMotor = "wpi/ExpansionHubMotor.hpp"
ExpansionHubPidConstants = "wpi/ExpansionHubPidConstants.hpp"
ExpansionHubServo = "wpi/ExpansionHubServo.hpp"
@@ -67,22 +66,22 @@ ExpansionHubServo = "wpi/ExpansionHubServo.hpp"
To fix this, you can copy the lines from the console, and add them to the pyproject.toml file, located here `wpilibc/src/main/python/pyproject.toml`
## 2. update-yaml
This process parses all of the header files, and creates a representation of the classes / enums / etc in yaml. Occasionally some functions might be ignored or need custom pybind code, which can be added to these files by the user.
This process parses all of the header files, and creates a representation of the classes / enums / etc in YAML. Occasionally, some functions might be ignored or need custom pybind code, which can be added to these files by the user.
There is a bazel task that you can run to automatically update the files:
There is a Bazel task that you can run to automatically update the files:
`bazel run //wpilibc:write_robotpy-wpilib-update-yaml`
## 3. generate-build-info
This step takes the yaml files, and auto generates a bazel build script for the library.
This step takes the yaml files, and auto-generates a Bazel build script for the library.
There is a bazel task that you can run to automatically update the files:
There is a Bazel task that you can run to automatically update the files:
`bazel run //wpilibc:robotpy-wpilib-generator.generate_build_info`
## semiwrap errors
If all of these steps above go smoothly and have their tests pass, but the generated cpp files still won't compile, it is possible that either an update needs to be made to the semiwrap tool to handle the new complex functionality, the new functionality can be ignored, or the new functionality might be better handled with a custom pybind11 implementation. In any case, it is best to reach out to the robotpy team for guidance.
If all of the above steps go smoothly and have their tests pass, but the generated cpp files still won't compile, it is possible that either an update needs to be made to the semiwrap tool to handle the new complex functionality, the new functionality can be ignored, or the new functionality might be better handled with a custom pybind11 implementation. In any case, it is best to reach out to the RobotPy team for guidance.
## Running multiple projects at once
Each project has its own `scan-headers` and various pregeneration tools, but you can run all of them at once with the following commands. Note: Sometimes if something in the dependency chain for a library fails, these amalgamation commands will also fail. If that happens, fix your way up the dependency chain project by project.

View File

@@ -3,8 +3,9 @@
[![Gradle](https://github.com/wpilibsuite/allwpilib/actions/workflows/gradle.yml/badge.svg?branch=main)](https://github.com/wpilibsuite/allwpilib/actions/workflows/gradle.yml)
[![C++ Documentation](https://img.shields.io/badge/documentation-c%2B%2B-blue)](https://github.wpilib.org/allwpilib/docs/development/cpp/)
[![Java Documentation](https://img.shields.io/badge/documentation-java-orange)](https://github.wpilib.org/allwpilib/docs/development/java/)
[![Python Documentation](https://img.shields.io/badge/documentation-python-blue)](https://robotpy.readthedocs.io/projects/robotpy/en/latest/)
Welcome to the WPILib project. This repository contains the HAL, WPILibJ, and WPILibC projects. These are the core libraries for creating robot programs for the roboRIO.
Welcome to the WPILib project. This repository contains the HAL, CameraServer, Commands (v2 and v3), NTCore, WPIMath, and WPILib projects. These are the core libraries for creating robot programs for Systemcore.
- [WPILib Project](#wpilib-project)
- [WPILib Mission](#wpilib-mission)
@@ -25,7 +26,7 @@ Welcome to the WPILib project. This repository contains the HAL, WPILibJ, and WP
## WPILib Mission
The WPILib Mission is to enable FIRST Robotics teams to focus on writing game-specific software rather than focusing on hardware details - "raise the floor, don't lower the ceiling". We work to enable teams with limited programming knowledge and/or mentor experience to be as successful as possible, while not hampering the abilities of teams with more advanced programming capabilities. We support Kit of Parts control system components directly in the library. We also strive to keep parity between major features of each language (Java, C++, Python, and NI's LabVIEW), so that teams aren't at a disadvantage for choosing a specific programming language. WPILib is an open source project, licensed under the BSD 3-clause license. You can find a copy of the license [here](LICENSE.md).
The WPILib Mission is to enable FIRST Robotics Competition (FRC) and FIRST Tech Challenge (FTC) teams to focus on writing game-specific software rather than focusing on hardware details - "raise the floor, don't lower the ceiling". We work to enable teams with limited programming knowledge and/or mentor experience to be as successful as possible, while not hampering the abilities of teams with more advanced programming capabilities. We support the FRC Kit of Parts/FTC control system components directly in the library. We also strive to keep parity between major features of each language (Java, C++, and Python), so that teams aren't at a disadvantage for choosing a specific programming language. WPILib is an open source project, licensed under the BSD 3-clause license. You can find a copy of the license [here](LICENSE.md).
# Quick Start
@@ -38,29 +39,26 @@ Below is a list of instructions that guide you through cloning, building, publis
# Building WPILib
Using Gradle makes building WPILib very straightforward. It only has a few dependencies on outside tools, such as the ARM cross compiler for creating roboRIO binaries.
Using Gradle makes building WPILib very straightforward. It only has a few dependencies on outside tools, such as the ARM cross compiler for creating Systemcore binaries.
## Requirements
- [JDK 21](https://adoptium.net/temurin/releases/?version=21)
- [JDK 25](https://adoptium.net/temurin/releases/?version=25)
- Note that the JRE is insufficient; the full JDK is required
- On Ubuntu, run `sudo apt install openjdk-21-jdk`
- On Windows, install the JDK 21 .msi from the link above
- On macOS, install the JDK 21 .pkg from the link above
- On Ubuntu, run `sudo apt install openjdk-25-jdk`
- On Windows, install the JDK 25 .msi from the link above
- On macOS, install the JDK 25 .pkg from the link above
- C++ compiler
- On Linux, install GCC 11 or greater
- On Windows, install [Visual Studio Community 2022](https://visualstudio.microsoft.com/vs/community/) and select the C++ programming language during installation (Gradle can't use the build tools for Visual Studio)
- On macOS, install the Xcode command-line build tools via `xcode-select --install`. Xcode 14 or later is required.
- ARM compiler toolchain
- Run `./gradlew installRoboRioToolchain` after cloning this repository
- If the WPILib installer was used, this toolchain is already installed
- Raspberry Pi toolchain (optional)
- Run `./gradlew installArm32Toolchain` after cloning this repository
- Run `./gradlew installArm64Toolchain` after cloning this repository
- Systemcore toolchain (required for Systemcore development)
- Run `./gradlew installSystemCoreToolchain` after cloning this repository
- If the WPILib installer was used, this toolchain is already installed
On macOS ARM, run `softwareupdate --install-rosetta`. This is necessary to be able to use the macOS x86 roboRIO toolchain on ARM.
On macOS ARM, run `softwareupdate --install-rosetta`. This is necessary to be able to use the macOS x86 Systemcore toolchain on ARM.
On linux, run `sudo apt install libx11-dev libgl-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev` to be able to build things depending on glfw.
@@ -129,10 +127,10 @@ Please read the documentation available [here](DevelopmentBuilds.md)
### Custom toolchain location
If you have installed the FRC Toolchain to a directory other than the default, or if the Toolchain location is not on your System PATH, you can pass the `toolChainPath` property to specify where it is located. Example:
If you have installed the WPILib Toolchain to a directory other than the default, or if the Toolchain location is not on your System PATH, you can pass the `toolChainPath` property to specify where it is located. Example:
```bash
./gradlew build -PtoolChainPath=some/path/to/frc/toolchain/bin
./gradlew build -PtoolChainPath=some/path/to/wpilib/toolchain/bin
```
### Formatting/linting
@@ -183,15 +181,15 @@ If you are building to test with other dependencies or just want to export the b
- stable - Publishes to ~/releases/maven/stable.
- release - Publishes to ~/releases/maven/release.
The maven artifacts are described in [MavenArtifacts.md](MavenArtifacts.md)
The Maven artifacts are described in [MavenArtifacts.md](MavenArtifacts.md)
## Structure and Organization
The main WPILib code you're probably looking for is in WPILibJ and WPILibC. Those directories are split into shared, sim, and athena. Athena contains the WPILib code meant to run on your roboRIO. Sim is WPILib code meant to run on your computer, and shared is code shared between the two. Shared code must be platform-independent, since it will be compiled with both the ARM cross-compiler and whatever desktop compiler you are using (g++, msvc, etc...).
The main WPILib code you're probably looking for is in WPILibJ and WPILibC. Those directories contain the high-level hardware/robot classes used for interacting with hardware, the Driver Station, and contain the core framework that almost all robot projects use.
The integration test directories for C++ and Java contain test code that runs on our test-system. When you submit code for review, it is tested by those programs. If you add new functionality you should make sure to write tests for it so we don't break it in the future.
The src/test directories under each subproject for C++ and Java contain test code that runs on GitHub Actions. When you submit code for review, it is tested by GitHub Actions' runners. If you add new functionality you should make sure to write tests for it so we don't break it in the future.
The hal directory contains more C++ code meant to run on the roboRIO. HAL is an acronym for "Hardware Abstraction Layer", and it interfaces with the NI Libraries. The NI Libraries contain the low-level code for controlling devices on your robot. The NI Libraries are found in the [ni-libraries](https://github.com/wpilibsuite/ni-libraries) project.
The hal directory contains more C++ code meant to run on Systemcore. HAL is an acronym for "Hardware Abstraction Layer", and it interfaces with the robot controller to enable hardware interactions. The HAL is split into cpp, sim, and systemcore. The systemcore directory contains the WPILib code meant to run on your Systemcore. Sim is WPILib code meant to run on your computer, and cpp is code shared between the two. Code in the cpp directory must be platform-independent, since it will be compiled with both the ARM cross-compiler and whatever desktop compiler you are using (g++, MSVC, etc...).
The upstream_utils directory contains scripts for updating copies of thirdparty code in the repository.

View File

@@ -19,18 +19,12 @@ Google Test thirdparty/googletest/include
thirdparty/googletest/src
LLVM wpiutil/src/main/native/thirdparty/llvm
wpiutil/src/test/native/cpp/llvm/
JSON for Modern C++ wpiutil/src/main/native/thirdparty/json
wpiutil/src/test/native/cpp/json/
JSON for Classic C++ wpiutil/src/main/native/thirdparty/json
libuv wpinet/src/main/native/thirdparty/libuv/
fmtlib wpiutil/src/main/native/thirdparty/fmtlib/
sigslot wpiutil/src/main/native/thirdparty/sigslot
tcpsockets wpinet/src/main/native/thirdparty/tcpsockets
MPack wpiutil/src/main/native/thirdparty/mpack
Bootstrap wpinet/src/main/native/resources/bootstrap-*
CoreUI wpinet/src/main/native/resources/coreui-*
Feather Icons wpinet/src/main/native/resources/feather-*
jQuery wpinet/src/main/native/resources/jquery-*
popper.js wpinet/src/main/native/resources/popper-*
units wpimath/src/main/native/include/wpi/units/
Eigen wpimath/src/main/native/thirdparty/eigen/include/
Team 254 Library wpimath/src/main/java/org/wpilib/math/spline/SplineParameterizer.java
@@ -43,6 +37,7 @@ V8 export-template wpiutil/src/main/native/include/wpi/SymbolExports.hpp
GCEM wpimath/src/main/native/thirdparty/gcem/include/
Sleipnir wpimath/src/main/native/thirdparty/sleipnir
Debugging wpiutil/src/main/native/thirdparty/debugging
double-conversion wpiutil/src/main/native/thirdparty/double-conversion
argparse wpiutil/src/main/native/thirdparty/argparse/include/wpi/util/argparse.hpp
apriltag apriltag/src/main/native/thirdparty/apriltag
glfw thirdparty/imgui_suite/glfw
@@ -53,6 +48,7 @@ upb wpiutil/src/main/native/thirdparty/upb
mrcal tools/wpical/src/main/native/thirdparty/mrcal
libdogleg tools/wpical/src/main/native/thirdparty/libdogleg
Simd hal/src/main/native/systemcore/simd
AdvantageScope fields/src/main/native/resources/org/wpilib/fields/ftc
Additionally, glfw and nanopb were modified for use in WPILib.
@@ -369,35 +365,22 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
JSON for Modern C++ License
==============================================================================
============================
JSON for Classic C++ License
============================
Copyright 2024 Mozilla Foundation
__ _____ _____ _____
__| | __| | | | JSON for Modern C++
| | |__ | | | | | | version 2.1.1
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
http://www.apache.org/licenses/LICENSE-2.0
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================
@@ -498,128 +481,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==============================================================================
Bootstrap License
==============================================================================
Copyright (c) 2011-2018 Twitter, Inc.
Copyright (c) 2011-2018 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
==============================================================================
CoreUI License
==============================================================================
Copyright (c) 2018 creativeLabs tukasz Holeczek.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
==============================================================================
Feather Icons License
==============================================================================
Copyright (c) 2013-2017 Cole Bemis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==============================================================================
jQuery License
==============================================================================
Copyright JS Foundation and other contributors, https://js.foundation/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==============================================================================
popper.js License
==============================================================================
Copyright (c) 2016 Federico Zivolo and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=============
units License
=============
@@ -1184,6 +1045,36 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================
double-conversion License
=========================
Copyright 2006-2011, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================
argparse License
================
@@ -1673,3 +1564,34 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
============
AdvantageScope License
============
Copyright (c) 2021-2026 Littleton Robotics. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of Littleton Robotics, FRC 6328 ("Mechanical Advantage"),
AdvantageScope, nor the names of other AdvantageScope contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY LITTLETON ROBOTICS AND OTHER ADVANTAGESCOPE
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
LITTLETON ROBOTICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -21,8 +21,8 @@ http_archive(
http_archive(
name = "bzlmodrio-opencv",
sha256 = "867ec3e90b7efc30ff6eb68d14050e7f1e800656d390505b135069f080c5cd91",
url = "https://github.com/wpilibsuite/bzlmodRio-opencv/releases/download/2025.4.10.0-3.bcr5/bzlmodRio-opencv-2025.4.10.0-3.bcr5.tar.gz",
sha256 = "947df6f399593a54779b7706da8abaa43865769e02b15533519c800e23be419f",
url = "https://github.com/wpilibsuite/bzlmodRio-opencv/releases/download/2027.4.13.0-3/bzlmodRio-opencv-2027.4.13.0-3.tar.gz",
)
load("@bzlmodrio-opencv//:maven_cpp_deps.bzl", "setup_legacy_bzlmodrio_opencv_cpp_dependencies")

View File

@@ -140,6 +140,9 @@ wpilib_jni_java_library(
maven_artifact_name = "apriltag-java",
maven_group_id = "org.wpilib.apriltag",
native_libs = [":apriltagjni"],
plugins = [
"//:avaje_jsonb_generator",
],
resource_strip_prefix = "apriltag/src/main/native/resources",
resources = glob(["src/main/native/resources/**"]),
visibility = ["//visibility:public"],
@@ -147,9 +150,8 @@ wpilib_jni_java_library(
"//wpimath:wpimath-java",
"//wpiutil:wpiutil-java",
"@bzlmodrio-opencv//libraries/java/opencv",
"@maven//:com_fasterxml_jackson_core_jackson_annotations",
"@maven//:com_fasterxml_jackson_core_jackson_core",
"@maven//:com_fasterxml_jackson_core_jackson_databind",
"@maven//:io_avaje_avaje_json_core",
"@maven//:io_avaje_avaje_jsonb",
],
)
@@ -182,7 +184,7 @@ wpilib_java_junit5_test(
"//wpimath:wpimath-java",
"//wpiutil:wpiutil-java",
"@bzlmodrio-opencv//libraries/java/opencv",
"@maven//:com_fasterxml_jackson_core_jackson_databind",
"@maven//:io_avaje_avaje_jsonb",
],
)

View File

@@ -39,7 +39,7 @@ if(WITH_JAVA)
set(CMAKE_JNI_TARGET true)
file(GLOB EJML_JARS "${WPILIB_BINARY_DIR}/wpimath/thirdparty/ejml/*.jar")
file(GLOB JACKSON_JARS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson/*.jar")
file(GLOB AVAJE_JARS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/avaje/*.jar")
find_file(
OPENCV_JAR_FILE
NAMES opencv-${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.jar
@@ -69,7 +69,7 @@ if(WITH_JAVA)
wpiutil_jar
${EJML_JARS}
${OPENCV_JAR_FILE}
${JACKSON_JARS}
${AVAJE_JARS}
OUTPUT_NAME apriltag
OUTPUT_DIR ${WPILIB_BINARY_DIR}/${java_lib_dest}
GENERATE_NATIVE_HEADERS apriltag_jni_headers
@@ -120,7 +120,7 @@ add_library(apriltag ${apriltag_native_src} ${apriltag_resources_src} ${apriltag
set_target_properties(apriltag PROPERTIES DEBUG_POSTFIX "d")
set_property(TARGET apriltag PROPERTY FOLDER "libraries")
target_compile_features(apriltag PUBLIC cxx_std_20)
target_compile_features(apriltag PUBLIC cxx_std_23)
wpilib_target_warnings(apriltag)
target_link_libraries(apriltag wpimath)

View File

@@ -1,10 +1,12 @@
# AprilTag
A C++ wrapper around the [University of Michigan's AprilTag detector](https://github.com/AprilRobotics/apriltag), alongside a vendored copy of their code with some patches (patches are located in [upstream_utils](../upstream_utils/apriltag_patches/)).
## Adding new field to AprilTagFields
### Adding field JSON
1. Add a field layout CSV file to `src/main/native/resources/edu/wpi/first/apriltag`
1. Add a field layout CSV file to `src/main/native/resources/org/wpilib/vision/apriltag`
1. See docstring in `convert_apriltag_layouts.py` for more
2. Run `convert_apriltag_layouts.py` in the same directory as this readme to generate the JSON
3. That script overwrites all generated JSONs, so undo undesired changes if necessary
@@ -14,15 +16,15 @@
### Java updates
1. Update `src/main/java/edu/wpi/first/apriltag/AprilTagFields.java`
1. Update `src/main/java/org/wpilib/vision/apriltag/AprilTagFields.java`
1. Add enum value for new field to `AprilTagFields`
2. Update `AprilTagFields.kDefaultField` if necessary
### C++ updates
1. Update `src/main/native/include/frc/apriltag/AprilTagFields.h`
1. Update `src/main/native/include/wpi/apriltag/AprilTagFields.hpp`
1. Add enum value for new field to `AprilTagFields`
2. Update `AprilTagFields::kDefaultField` if necessary
2. Update `src/main/native/cpp/AprilTagFields.cpp`
2. Update `src/main/native/cpp/AprilTagFieldLayout.cpp`
1. Add resource getter prototype like `std::string_view GetResource_2024_crescendo_json()`
2. Add case for new field to switch in `LoadAprilTagLayoutField()`
2. Add case for new field to switch in `LoadField(AprilTagField field)`

View File

@@ -46,6 +46,7 @@ apply from: "${rootDir}/shared/opencv.gradle"
dependencies {
implementation project(':wpimath')
annotationProcessor libs.avaje.jsonb.generator
}
sourceSets {

View File

@@ -4,22 +4,22 @@
package org.wpilib.vision.apriltag;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.avaje.jsonb.Json;
import java.util.Objects;
import org.wpilib.math.geometry.Pose3d;
import org.wpilib.util.RawFrame;
import org.wpilib.vision.apriltag.jni.AprilTagJNI;
/** Represents an AprilTag's metadata. */
@SuppressWarnings("MemberName")
@Json
public class AprilTag {
/** The tag's ID. */
@JsonProperty(value = "ID")
@Json.Property("ID")
@SuppressWarnings("PMD.PublicFieldNamingConvention")
public int ID;
/** The tag's pose. */
@JsonProperty(value = "pose")
@Json.Property("pose")
public Pose3d pose;
/**
@@ -29,10 +29,8 @@ public class AprilTag {
* @param pose The tag's pose.
*/
@SuppressWarnings("ParameterName")
@JsonCreator
public AprilTag(
@JsonProperty(required = true, value = "ID") int ID,
@JsonProperty(required = true, value = "pose") Pose3d pose) {
@Json.Creator
public AprilTag(int ID, Pose3d pose) {
this.ID = ID;
this.pose = pose;
}

View File

@@ -14,7 +14,6 @@ import org.wpilib.vision.apriltag.jni.AprilTagJNI;
*/
public class AprilTagDetector implements AutoCloseable {
/** Detector configuration. */
@SuppressWarnings("MemberName")
public static class Config {
/**
* How many threads should be used for computation. Default is single-threaded operation (1
@@ -110,7 +109,6 @@ public class AprilTagDetector implements AutoCloseable {
}
/** Quad threshold parameters. */
@SuppressWarnings("MemberName")
public static class QuadThresholdParameters {
/** Threshold used to reject quads containing too few pixels. Default is 300 pixels. */
public int minClusterPixels = 300;

View File

@@ -4,17 +4,12 @@
package org.wpilib.vision.apriltag;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.avaje.jsonb.Json;
import io.avaje.jsonb.Jsonb;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
@@ -43,8 +38,7 @@ import org.wpilib.math.geometry.Translation3d;
* <p>Tag poses represent the center of the tag, with a zero rotation representing a tag that is
* upright and facing away from the (blue) alliance wall (that is, towards the opposing alliance).
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE)
@Json
public class AprilTagFieldLayout {
/** Common origin positions for the AprilTag coordinate system. */
public enum OriginPosition {
@@ -54,12 +48,12 @@ public class AprilTagFieldLayout {
kRedAllianceWallRightSide,
}
private final Map<Integer, AprilTag> m_apriltags = new HashMap<>();
@Json.Ignore private final Map<Integer, AprilTag> m_apriltags = new HashMap<>();
@JsonProperty(value = "field")
private FieldDimensions m_fieldDimensions;
@Json.Property("field")
FieldDimensions m_fieldDimensions;
private Pose3d m_origin;
@Json.Ignore private Pose3d m_origin;
/**
* Construct a new AprilTagFieldLayout with values imported from a JSON file.
@@ -79,7 +73,7 @@ public class AprilTagFieldLayout {
*/
public AprilTagFieldLayout(Path path) throws IOException {
AprilTagFieldLayout layout =
new ObjectMapper().readValue(path.toFile(), AprilTagFieldLayout.class);
Jsonb.instance().type(AprilTagFieldLayout.class).fromJson(Files.newBufferedReader(path));
m_apriltags.putAll(layout.m_apriltags);
m_fieldDimensions = layout.m_fieldDimensions;
setOrigin(OriginPosition.kBlueAllianceWallRightSide);
@@ -96,10 +90,10 @@ public class AprilTagFieldLayout {
this(apriltags, new FieldDimensions(fieldLength, fieldWidth));
}
@JsonCreator
private AprilTagFieldLayout(
@JsonProperty(required = true, value = "tags") List<AprilTag> apriltags,
@JsonProperty(required = true, value = "field") FieldDimensions fieldDimensions) {
@Json.Creator
AprilTagFieldLayout(
@Json.Alias("tags") List<AprilTag> apriltags,
@Json.Alias("field") FieldDimensions fieldDimensions) {
// To ensure the underlying semantics don't change with what kind of list is passed in
for (AprilTag tag : apriltags) {
m_apriltags.put(tag.ID, tag);
@@ -113,7 +107,7 @@ public class AprilTagFieldLayout {
*
* @return The {@link AprilTag AprilTags} used in this layout.
*/
@JsonProperty("tags")
@Json.Property("tags")
public List<AprilTag> getTags() {
return new ArrayList<>(m_apriltags.values());
}
@@ -123,7 +117,6 @@ public class AprilTagFieldLayout {
*
* @return length, in meters
*/
@JsonIgnore
public double getFieldLength() {
return m_fieldDimensions.fieldLength;
}
@@ -133,7 +126,6 @@ public class AprilTagFieldLayout {
*
* @return width, in meters
*/
@JsonIgnore
public double getFieldWidth() {
return m_fieldDimensions.fieldWidth;
}
@@ -147,7 +139,6 @@ public class AprilTagFieldLayout {
*
* @param origin The predefined origin
*/
@JsonIgnore
public final void setOrigin(OriginPosition origin) {
var pose =
switch (origin) {
@@ -168,7 +159,6 @@ public class AprilTagFieldLayout {
*
* @param origin The new origin for tag transformations
*/
@JsonIgnore
public final void setOrigin(Pose3d origin) {
m_origin = origin;
}
@@ -178,7 +168,6 @@ public class AprilTagFieldLayout {
*
* @return the origin
*/
@JsonIgnore
public Pose3d getOrigin() {
return m_origin;
}
@@ -216,7 +205,7 @@ public class AprilTagFieldLayout {
* @throws IOException If writing to the file fails.
*/
public void serialize(Path path) throws IOException {
new ObjectMapper().writeValue(path.toFile(), this);
Jsonb.instance().type(AprilTagFieldLayout.class).toJson(this, Files.newBufferedWriter(path));
}
/**
@@ -227,42 +216,38 @@ public class AprilTagFieldLayout {
* @throws UncheckedIOException If the layout does not exist.
*/
public static AprilTagFieldLayout loadField(AprilTagFields field) {
if (field.m_fieldLayout == null) {
if (field.fieldLayout == null) {
try {
field.m_fieldLayout = loadFromResource(field.m_resourceFile);
field.fieldLayout = loadFromResource(field.resourceFile);
} catch (IOException e) {
throw new UncheckedIOException(
"Could not load AprilTagFieldLayout from " + field.m_resourceFile, e);
"Could not load AprilTagFieldLayout from " + field.resourceFile, e);
}
}
// Copy layout because the layout's origin is mutable
return new AprilTagFieldLayout(
field.m_fieldLayout.getTags(),
field.m_fieldLayout.getFieldLength(),
field.m_fieldLayout.getFieldWidth());
field.fieldLayout.getTags(),
field.fieldLayout.getFieldLength(),
field.fieldLayout.getFieldWidth());
}
/**
* Deserializes a field layout from a resource within a internal jar file.
*
* <p>Users should use {@link AprilTagFields#loadAprilTagLayoutField()} to load official layouts
* and {@link #AprilTagFieldLayout(String)} for custom layouts.
* <p>Users should use {@link #loadField(AprilTagFields)} to load official layouts and {@link
* #AprilTagFieldLayout(String)} for custom layouts.
*
* @param resourcePath The absolute path of the resource
* @return The deserialized layout
* @throws IOException If the resource could not be loaded
*/
public static AprilTagFieldLayout loadFromResource(String resourcePath) throws IOException {
InputStream stream = AprilTagFieldLayout.class.getResourceAsStream(resourcePath);
if (stream == null) {
// Class.getResourceAsStream() returns null if the resource does not exist.
throw new IOException("Could not locate resource: " + resourcePath);
}
InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8);
try {
return new ObjectMapper().readerFor(AprilTagFieldLayout.class).readValue(reader);
} catch (IOException e) {
throw new IOException("Failed to load AprilTagFieldLayout: " + resourcePath);
try (InputStream stream = AprilTagFieldLayout.class.getResourceAsStream(resourcePath)) {
if (stream == null) {
// Class.getResourceAsStream() returns null if the resource does not exist.
throw new IOException("Could not locate resource: " + resourcePath);
}
return Jsonb.instance().type(AprilTagFieldLayout.class).fromJson(stream);
}
}
@@ -278,21 +263,17 @@ public class AprilTagFieldLayout {
return Objects.hash(m_apriltags, m_origin);
}
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE)
private static class FieldDimensions {
@SuppressWarnings("MemberName")
@JsonProperty(value = "length")
static class FieldDimensions {
@Json.Property(value = "length")
public final double fieldLength;
@SuppressWarnings("MemberName")
@JsonProperty(value = "width")
@Json.Property(value = "width")
public final double fieldWidth;
@JsonCreator()
@Json.Creator()
FieldDimensions(
@JsonProperty(required = true, value = "length") double fieldLength,
@JsonProperty(required = true, value = "width") double fieldWidth) {
@Json.Alias(value = "length") double fieldLength,
@Json.Alias(value = "width") double fieldWidth) {
this.fieldLength = fieldLength;
this.fieldWidth = fieldWidth;
}

View File

@@ -4,8 +4,6 @@
package org.wpilib.vision.apriltag;
import java.io.UncheckedIOException;
/** Loadable AprilTag field layouts. */
public enum AprilTagFields {
/** 2022 Rapid React. */
@@ -30,23 +28,11 @@ public enum AprilTagFields {
public static final AprilTagFields kDefaultField = k2026RebuiltWelded;
/** Resource filename. */
public final String m_resourceFile;
public final String resourceFile;
AprilTagFieldLayout m_fieldLayout;
AprilTagFieldLayout fieldLayout;
AprilTagFields(String resourceFile) {
m_resourceFile = kBaseResourceDir + resourceFile;
}
/**
* Get a {@link AprilTagFieldLayout} from the resource JSON.
*
* @return AprilTagFieldLayout of the field
* @throws UncheckedIOException If the layout does not exist
* @deprecated Use {@link AprilTagFieldLayout#loadField(AprilTagFields)} instead.
*/
@Deprecated(forRemoval = true, since = "2025")
public AprilTagFieldLayout loadAprilTagLayoutField() {
return AprilTagFieldLayout.loadField(this);
this.resourceFile = kBaseResourceDir + resourceFile;
}
}

View File

@@ -7,7 +7,6 @@ package org.wpilib.vision.apriltag;
import org.wpilib.math.geometry.Transform3d;
/** A pair of AprilTag pose estimates. */
@SuppressWarnings("MemberName")
public class AprilTagPoseEstimate {
/**
* Constructs a pose estimate.

View File

@@ -10,7 +10,6 @@ import org.wpilib.vision.apriltag.jni.AprilTagJNI;
/** Pose estimators for AprilTag tags. */
public class AprilTagPoseEstimator {
/** Configuration for the pose estimator. */
@SuppressWarnings("MemberName")
public static class Config {
/**
* Creates a pose estimator configuration.

View File

@@ -52,10 +52,10 @@ bool AprilTag::Generate16h5AprilTagImage(wpi::util::RawFrame* frame, int id) {
}
void wpi::apriltag::to_json(wpi::util::json& json, const AprilTag& apriltag) {
json = wpi::util::json{{"ID", apriltag.ID}, {"pose", apriltag.pose}};
json = wpi::util::json::object("ID", apriltag.ID, "pose", apriltag.pose);
}
void wpi::apriltag::from_json(const wpi::util::json& json, AprilTag& apriltag) {
apriltag.ID = json.at("ID").get<int>();
apriltag.ID = json.at("ID").get_int();
apriltag.pose = json.at("pose").get<wpi::math::Pose3d>();
}

View File

@@ -22,16 +22,16 @@ AprilTagFieldLayout::AprilTagFieldLayout(std::string_view path) {
throw std::runtime_error(fmt::format("Cannot open file: {}", path));
}
wpi::util::json json =
wpi::util::json::parse(fileBuffer.value()->GetCharBuffer());
auto buf = fileBuffer.value()->GetCharBuffer();
auto json = wpi::util::json::parse_or_throw({buf.data(), buf.size()});
for (const auto& tag : json.at("tags").get<std::vector<AprilTag>>()) {
for (auto&& jtag : json.at("tags").get_array()) {
auto tag = jtag.get<AprilTag>();
m_apriltags[tag.ID] = tag;
}
m_fieldWidth =
wpi::units::meter_t{json.at("field").at("width").get<double>()};
m_fieldWidth = wpi::units::meter_t{json.at("field").at("width").get_number()};
m_fieldLength =
wpi::units::meter_t{json.at("field").at("length").get<double>()};
wpi::units::meter_t{json.at("field").at("length").get_number()};
}
AprilTagFieldLayout::AprilTagFieldLayout(std::vector<AprilTag> apriltags,
@@ -113,23 +113,24 @@ void wpi::apriltag::to_json(wpi::util::json& json,
tagVector.push_back(pair.second);
}
json = wpi::util::json{{"field",
{{"length", layout.m_fieldLength.value()},
{"width", layout.m_fieldWidth.value()}}},
{"tags", tagVector}};
auto field = wpi::util::json::object("length", layout.m_fieldLength.value(),
"width", layout.m_fieldWidth.value());
json = wpi::util::json::object("field", std::move(field), "tags",
std::move(tagVector));
}
void wpi::apriltag::from_json(const wpi::util::json& json,
AprilTagFieldLayout& layout) {
layout.m_apriltags.clear();
for (const auto& tag : json.at("tags").get<std::vector<AprilTag>>()) {
for (auto&& jtag : json.at("tags").get_array()) {
auto tag = jtag.get<AprilTag>();
layout.m_apriltags[tag.ID] = tag;
}
layout.m_fieldLength =
wpi::units::meter_t{json.at("field").at("length").get<double>()};
wpi::units::meter_t{json.at("field").at("length").get_number()};
layout.m_fieldWidth =
wpi::units::meter_t{json.at("field").at("width").get<double>()};
wpi::units::meter_t{json.at("field").at("width").get_number()};
}
// Use namespace declaration for forward declaration
@@ -174,11 +175,6 @@ AprilTagFieldLayout AprilTagFieldLayout::LoadField(AprilTagField field) {
throw std::invalid_argument("Invalid Field");
}
wpi::util::json json = wpi::util::json::parse(fieldString);
wpi::util::json json = wpi::util::json::parse_or_throw(fieldString);
return json.get<AprilTagFieldLayout>();
}
AprilTagFieldLayout wpi::apriltag::LoadAprilTagLayoutField(
AprilTagField field) {
return AprilTagFieldLayout::LoadField(field);
}

View File

@@ -7,7 +7,10 @@
#include "wpi/math/geometry/Pose3d.hpp"
#include "wpi/util/RawFrame.hpp"
#include "wpi/util/SymbolExports.hpp"
#include "wpi/util/json_fwd.hpp"
namespace wpi::util {
class json;
} // namespace wpi::util
namespace wpi::apriltag {

View File

@@ -14,7 +14,10 @@
#include "wpi/math/geometry/Pose3d.hpp"
#include "wpi/units/length.hpp"
#include "wpi/util/SymbolExports.hpp"
#include "wpi/util/json_fwd.hpp"
namespace wpi::util {
class json;
} // namespace wpi::util
namespace wpi::apriltag {
/**
@@ -161,15 +164,4 @@ void to_json(wpi::util::json& json, const AprilTagFieldLayout& layout);
WPILIB_DLLEXPORT
void from_json(const wpi::util::json& json, AprilTagFieldLayout& layout);
/**
* Loads an AprilTagFieldLayout from a predefined field
*
* @param field The predefined field
* @return AprilTagFieldLayout of the field
* @deprecated Use AprilTagFieldLayout::LoadField() instead
*/
[[deprecated("Use AprilTagFieldLayout::LoadField() instead")]]
WPILIB_DLLEXPORT AprilTagFieldLayout
LoadAprilTagLayoutField(AprilTagField field);
} // namespace wpi::apriltag

View File

@@ -2,7 +2,7 @@
build-backend = "hatchling.build"
requires = [
"semiwrap~=0.3.0",
"hatch-meson~=0.1.0",
"hatch-meson~=0.1.2",
"hatch-robotpy~=0.2.1",
"hatchling",
"robotpy-native-apriltag==0.0.0",
@@ -63,7 +63,7 @@ wraps = ["robotpy-native-apriltag"]
depends = ["wpiutil", "wpimath"]
[tool.semiwrap.extension_modules."robotpy_apriltag._apriltag".headers]
# frc/apriltag
# wpi/apriltag
AprilTag = "wpi/apriltag/AprilTag.hpp"
AprilTagDetection = "wpi/apriltag/AprilTagDetection.hpp"
AprilTagDetector = "wpi/apriltag/AprilTagDetector.hpp"

View File

@@ -3,8 +3,6 @@ functions:
ignore: true
from_json:
ignore: true
LoadAprilTagLayoutField:
ignore: true
classes:
wpi::apriltag::AprilTagFieldLayout:
enums:

View File

@@ -25,7 +25,6 @@ import org.wpilib.math.util.Units;
import org.wpilib.util.runtime.RuntimeLoader;
class AprilTagDetectorTest {
@SuppressWarnings("MemberName")
AprilTagDetector detector;
@BeforeAll
@@ -110,7 +109,6 @@ class AprilTagDetectorTest {
detector.removeFamily("tag16h5");
}
@SuppressWarnings("PMD.AssignmentInOperand")
public Mat loadImage(String resource) throws IOException {
Mat encoded;
try (InputStream is = getClass().getResource(resource).openStream()) {

View File

@@ -13,7 +13,7 @@ class AprilTagGenerationTest {
@Test
void test36h11() {
var frame = AprilTag.generate36h11AprilTagImage(1);
assertEquals(PixelFormat.kGray, frame.getPixelFormat());
assertEquals(PixelFormat.GRAY, frame.getPixelFormat());
assertEquals(10, frame.getWidth());
assertEquals(10, frame.getHeight());
int stride = frame.getStride();

View File

@@ -7,7 +7,7 @@ package org.wpilib.vision.apriltag;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.avaje.jsonb.Jsonb;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.wpilib.math.geometry.Pose3d;
@@ -25,13 +25,9 @@ class AprilTagSerializationTest {
Units.feetToMeters(54.0),
Units.feetToMeters(27.0));
var objectMapper = new ObjectMapper();
var layoutType = Jsonb.instance().type(AprilTagFieldLayout.class);
var deserialized =
assertDoesNotThrow(
() ->
objectMapper.readValue(
objectMapper.writeValueAsString(layout), AprilTagFieldLayout.class));
var deserialized = assertDoesNotThrow(() -> layoutType.fromJson(layoutType.toJson(layout)));
assertEquals(layout, deserialized);
}

View File

@@ -6,7 +6,7 @@ file(GLOB benchmarkCpp_src src/main/native/cpp/*.cpp src/main/native/thirdparty/
add_executable(benchmarkCpp ${benchmarkCpp_src})
target_compile_features(benchmarkCpp PUBLIC cxx_std_20)
target_compile_features(benchmarkCpp PUBLIC cxx_std_23)
wpilib_target_warnings(benchmarkCpp)

View File

@@ -16,7 +16,7 @@ This command runs the C++ benchmarks on desktop.
./gradlew benchmark:runCpp
```
## Deploy to a roboRIO
## Deploy to a Systemcore
This project can only deploy over USB. If an alternate IP address is preferred, the `address` block in benchmark/build.gradle can be changed to point to another address.
@@ -30,19 +30,20 @@ This command deploys the C++ project with all dependencies statically linked.
./gradlew benchmark:deployStatic
```
This command deploys the Java project and all required dependencies. It also installs the JRE if it's not currently installed.
This command deploys the Java project and all required dependencies.
```bash
./gradlew benchmark:deployJava
```
Those commands won't start the robot executable, so you have to manually ssh in and start it. The following command will do that.
```bash
ssh lvuser@172.22.11.2 frcRunRobot.sh
ssh systemcore@robot.local sudo systemctl stop robot
ssh systemcore@robot.local sudo ~/robotCommand
```
Console log prints will appear in the terminal.
Deploying any of these to the roboRIO will disable the current startup project until it is redeployed.
Deploying any of these to a Systemcore will disable the current startup project until it is redeployed.
## Faster builds

View File

@@ -37,6 +37,11 @@ application {
apply plugin: 'com.gradleup.shadow'
shadowJar {
mergeServiceFiles()
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
repositories {
maven {
url = 'https://frcmaven.wpi.edu/artifactory/ex-mvn'
@@ -93,35 +98,35 @@ deploy {
all {
postdeploy << { ctx ->
ctx.execute("sync")
ctx.execute("sudo ldconfig /home/systemcore/frc/third-party/lib")
ctx.execute("sudo ldconfig /home/systemcore/wpilib/third-party/lib")
}
}
benchmarkCpp(NativeExecutableArtifact) {
libraryDirectory = '/usr/local/frc/third-party/lib'
libraryDirectory = '/home/systemcore/wpilib/third-party/lib'
def excludes = getLibraryFilter().getExcludes()
excludes.add('**/*.so.debug')
excludes.add('**/*.so.*.debug')
postdeploy << { ctx ->
ctx.execute("echo '/home/lvuser/benchmarkCpp' > /home/lvuser/robotCommand")
ctx.execute("chmod +x /home/lvuser/robotCommand; chown lvuser /home/lvuser/robotCommand")
ctx.execute("setcap cap_sys_nice+eip \"/home/lvuser/benchmarkCpp\"")
ctx.execute("echo '/home/systemcore/benchmarkCpp' > /home/systemcore/robotCommand")
ctx.execute("chmod +x /home/systemcore/robotCommand; chown systemcore /home/systemcore/robotCommand")
ctx.execute("setcap cap_sys_nice+eip \"/home/systemcore/benchmarkCpp\"")
ctx.execute('chmod +x benchmarkCpp')
}
}
benchmarkCppStatic(NativeExecutableArtifact) {
libraryDirectory = '/usr/local/frc/third-party/lib'
libraryDirectory = '/home/systemcore/wpilib/third-party/lib'
postdeploy << { ctx ->
ctx.execute("echo '/home/lvuser/benchmarkCppStatic' > /home/lvuser/robotCommand")
ctx.execute("chmod +x /home/lvuser/robotCommand; chown lvuser /home/lvuser/robotCommand")
ctx.execute("setcap cap_sys_nice+eip \"/home/lvuser/benchmarkCppStatic\"")
ctx.execute("echo '/home/systemcore/benchmarkCppStatic' > /home/systemcore/robotCommand")
ctx.execute("chmod +x /home/systemcore/robotCommand; chown systemcore /home/systemcore/robotCommand")
ctx.execute("setcap cap_sys_nice+eip \"/home/systemcore/benchmarkCppStatic\"")
ctx.execute('chmod +x benchmarkCppStatic')
}
}
benchmarkCppJava(NativeExecutableArtifact) {
libraryDirectory = '/usr/local/frc/third-party/lib'
libraryDirectory = '/home/systemcore/wpilib/third-party/lib'
def excludes = getLibraryFilter().getExcludes()
excludes.add('**/*.so.debug')
excludes.add('**/*.so.*.debug')
@@ -130,8 +135,8 @@ deploy {
benchmarkJava(JavaArtifact) {
jarTask = shadowJar
postdeploy << { ctx ->
ctx.execute("echo '/usr/local/frc/JRE/bin/java -XX:+UseSerialGC -Djava.library.path=/usr/local/frc/third-party/lib -Djava.lang.invoke.stringConcat=BC_SB -jar /home/lvuser/benchmark-all.jar' > /home/lvuser/robotCommand")
ctx.execute("chmod +x /home/lvuser/robotCommand; chown lvuser /home/lvuser/robotCommand")
ctx.execute("echo 'java -XX:+UseSerialGC -Djava.library.path=/home/systemcore/wpilib/third-party/lib -Djava.lang.invoke.stringConcat=BC_SB -jar /home/systemcore/benchmark-all.jar' > /home/systemcore/robotCommand")
ctx.execute("chmod +x /home/systemcore/robotCommand; chown systemcore /home/systemcore/robotCommand")
}
}
}

View File

@@ -0,0 +1,128 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source 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 wpilib.robot;
import static org.wpilib.math.autodiff.NumericalIntegration.rk4;
import static org.wpilib.math.autodiff.Variable.cos;
import static org.wpilib.math.autodiff.Variable.sin;
import static org.wpilib.math.autodiff.VariableMatrix.solve;
import static org.wpilib.math.optimization.Constraints.eq;
import static org.wpilib.math.optimization.Constraints.ge;
import static org.wpilib.math.optimization.Constraints.le;
import org.ejml.simple.SimpleMatrix;
import org.wpilib.math.autodiff.Variable;
import org.wpilib.math.autodiff.VariableMatrix;
import org.wpilib.math.optimization.Problem;
import org.wpilib.math.optimization.solver.Options;
import org.wpilib.math.util.MathUtil;
public final class CartPoleBenchmark {
private CartPoleBenchmark() {
// Utility class.
}
@SuppressWarnings("LocalVariableName")
private static VariableMatrix cartPoleDynamics(VariableMatrix x, VariableMatrix u) {
final double m_c = 5.0; // Cart mass (kg)
final double m_p = 0.5; // Pole mass (kg)
final double l = 0.5; // Pole length (m)
final double g = 9.806; // Acceleration due to gravity (m/s²)
var q = x.segment(0, 2);
var qdot = x.segment(2, 2);
var theta = q.get(1);
var thetadot = qdot.get(1);
// [ m_c + m_p m_p l cosθ]
// M(q) = [m_p l cosθ m_p l² ]
var M =
new VariableMatrix(
new Variable[][] {
{new Variable(m_c + m_p), cos(theta).times(m_p * l)},
{cos(theta).times(m_p * l), new Variable(m_p * Math.pow(l, 2))}
});
// [0 m_p lθ̇ sinθ]
// C(q, q̇) = [0 0 ]
var C =
new VariableMatrix(
new Variable[][] {
{new Variable(0), thetadot.times(-m_p * l).times(sin(theta))},
{new Variable(0), new Variable(0)}
});
// [ 0 ]
// τ_g(q) = [-m_p gl sinθ]
var tau_g =
new VariableMatrix(new Variable[][] {{new Variable(0)}, {sin(theta).times(-m_p * g * l)}});
// [1]
// B = [0]
var B = new VariableMatrix(new double[][] {{1}, {0}});
// q̈ = M⁻¹(q)(τ_g(q) C(q, q̇)q̇ + Bu)
var qddot = new VariableMatrix(4);
qddot.segment(0, 2).set(qdot);
qddot.segment(2, 2).set(solve(M, tau_g.minus(C.times(qdot)).plus(B.times(u))));
return qddot;
}
/** Cart-pole benchmark. */
public static void cartPole() {
final double T = 5.0; // s
final double dt = 0.05; // s
final int N = (int) (T / dt);
final double u_max = 20.0; // N
final double d_max = 2.0; // m
final var x_initial = new SimpleMatrix(new double[][] {{0.0}, {0.0}, {0.0}, {0.0}});
final var x_final = new SimpleMatrix(new double[][] {{1.0}, {Math.PI}, {0.0}, {0.0}});
var problem = new Problem();
// x = [q, q̇]ᵀ = [x, θ, ẋ, θ̇]ᵀ
var X = problem.decisionVariable(4, N + 1);
// Initial guess
for (int k = 0; k < N + 1; ++k) {
X.get(0, k).setValue(MathUtil.lerp(x_initial.get(0), x_final.get(0), (double) k / N));
X.get(1, k).setValue(MathUtil.lerp(x_initial.get(1), x_final.get(1), (double) k / N));
}
// u = f_x
var U = problem.decisionVariable(1, N);
// Initial conditions
problem.subjectTo(eq(X.col(0), x_initial));
// Final conditions
problem.subjectTo(eq(X.col(N), x_final));
// Cart position constraints
problem.subjectTo(ge(X.row(0), 0.0));
problem.subjectTo(le(X.row(0), d_max));
// Input constraints
problem.subjectTo(ge(U, -u_max));
problem.subjectTo(le(U, u_max));
// Dynamics constraints - RK4 integration
for (int k = 0; k < N; ++k) {
problem.subjectTo(
eq(X.col(k + 1), rk4(CartPoleBenchmark::cartPoleDynamics, X.col(k), U.col(k), dt)));
}
// Minimize sum squared inputs
var J = new Variable(0.0);
for (int k = 0; k < N; ++k) {
J = J.plus(U.col(k).T().times(U.col(k)).get(0));
}
problem.minimize(J);
problem.solve(new Options().withDiagnostics(true));
}
}

View File

@@ -37,6 +37,13 @@ public class Main {
new Runner(opt).run();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public void cartPole() {
CartPoleBenchmark.cartPole();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)

View File

@@ -103,7 +103,7 @@ BENCHMARK(BM_SetInsert)->Ranges({{1<<10, 8<<10}, {128, 512}});
// arbitrary set of arguments to run the microbenchmark on.
// The following example enumerates a dense range on
// one parameter, and a sparse range on the second.
static void CustomArguments(benchmark::internal::Benchmark* b) {
static void CustomArguments(benchmark::Benchmark* b) {
for (int i = 0; i <= 10; ++i)
for (int j = 32; j <= 1024*1024; j *= 8)
b->Args({i, j});
@@ -171,7 +171,6 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
#include <cassert>
#include <cstddef>
#include <functional>
#include <initializer_list>
#include <iosfwd>
#include <limits>
#include <map>
@@ -239,6 +238,16 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
_Pragma("diagnostic push") \
_Pragma("diag_suppress deprecated_entity_with_custom_message")
#define BENCHMARK_RESTORE_DEPRECATED_WARNING _Pragma("diagnostic pop")
#elif defined(_MSC_VER)
#define BENCHMARK_BUILTIN_EXPECT(x, y) x
#define BENCHMARK_DEPRECATED_MSG(msg) __declspec(deprecated(msg))
#define BENCHMARK_WARNING_MSG(msg) \
__pragma(message(__FILE__ "(" BENCHMARK_INTERNAL_TOSTRING( \
__LINE__) ") : warning note: " msg))
#define BENCHMARK_DISABLE_DEPRECATED_WARNING \
__pragma(warning(push)) \
__pragma(warning(disable : 4996))
#define BENCHMARK_RESTORE_DEPRECATED_WARNING __pragma(warning(pop))
#else
#define BENCHMARK_BUILTIN_EXPECT(x, y) x
#define BENCHMARK_DEPRECATED_MSG(msg)
@@ -476,10 +485,11 @@ void RegisterProfilerManager(ProfilerManager* profiler_manager);
// Add a key-value pair to output as part of the context stanza in the report.
BENCHMARK_EXPORT
void AddCustomContext(const std::string& key, const std::string& value);
void AddCustomContext(std::string key, std::string value);
class Benchmark;
namespace internal {
class Benchmark;
class BenchmarkImp;
class BenchmarkFamilies;
@@ -611,6 +621,17 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
_ReadWriteBarrier();
}
template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) {
internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
_ReadWriteBarrier();
}
template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) {
internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
_ReadWriteBarrier();
}
#else
template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) {
@@ -956,6 +977,8 @@ class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State {
BENCHMARK_ALWAYS_INLINE
std::string name() const { return name_; }
size_t range_size() const { return range_.size(); }
private:
// items we expect on the first cache line (ie 64 bytes of the struct)
// When total_iterations_ is 0, KeepRunning() and friends will return false.
@@ -1102,20 +1125,15 @@ struct ThreadRunnerBase {
virtual void RunThreads(const std::function<void(int)>& fn) = 0;
};
namespace internal {
// Define alias of ThreadRunner factory function type
using threadrunner_factory =
std::function<std::unique_ptr<ThreadRunnerBase>(int)>;
typedef void(Function)(State&);
// ------------------------------------------------------
// Benchmark registration object. The BENCHMARK() macro expands
// into an internal::Benchmark* object. Various methods can
// be called on this object to change the properties of the benchmark.
// Each method returns "this" so that multiple method calls can
// chained into one expression.
// Benchmark registration object. The BENCHMARK() macro expands into a
// Benchmark* object. Various methods can be called on this object to
// change the properties of the benchmark. Each method returns "this" so
// that multiple method calls can chained into one expression.
class BENCHMARK_EXPORT Benchmark {
public:
virtual ~Benchmark();
@@ -1206,7 +1224,7 @@ class BENCHMARK_EXPORT Benchmark {
// Pass this benchmark object to *func, which can customize
// the benchmark by calling various methods like Arg, Args,
// Threads, etc.
Benchmark* Apply(void (*custom_arguments)(Benchmark* benchmark));
Benchmark* Apply(const std::function<void(Benchmark* benchmark)>&);
// Set the range multiplier for non-dense range. If not called, the range
// multiplier kRangeMultiplier will be used.
@@ -1329,11 +1347,11 @@ class BENCHMARK_EXPORT Benchmark {
const char* GetArgName(int arg) const;
private:
friend class BenchmarkFamilies;
friend class BenchmarkInstance;
friend class internal::BenchmarkFamilies;
friend class internal::BenchmarkInstance;
std::string name_;
AggregationReportMode aggregation_report_mode_;
internal::AggregationReportMode aggregation_report_mode_;
std::vector<std::string> arg_names_; // Args for all benchmark runs
std::vector<std::vector<int64_t>> args_; // Args for all benchmark runs
@@ -1350,7 +1368,7 @@ class BENCHMARK_EXPORT Benchmark {
bool use_manual_time_;
BigO complexity_;
BigOFunc* complexity_lambda_;
std::vector<Statistics> statistics_;
std::vector<internal::Statistics> statistics_;
std::vector<int> thread_counts_;
callback_function setup_;
@@ -1361,17 +1379,28 @@ class BENCHMARK_EXPORT Benchmark {
BENCHMARK_DISALLOW_COPY_AND_ASSIGN(Benchmark);
};
namespace internal {
// clang-format off
typedef BENCHMARK_DEPRECATED_MSG("Use ::benchmark::Benchmark instead")
::benchmark::Benchmark Benchmark;
typedef BENCHMARK_DEPRECATED_MSG(
"Use ::benchmark::threadrunner_factory instead")
::benchmark::threadrunner_factory threadrunner_factory;
// clang-format on
typedef void(Function)(State&);
} // namespace internal
// Create and register a benchmark with the specified 'name' that invokes
// the specified functor 'fn'.
//
// RETURNS: A pointer to the registered benchmark.
internal::Benchmark* RegisterBenchmark(const std::string& name,
internal::Function* fn);
Benchmark* RegisterBenchmark(const std::string& name, internal::Function* fn);
template <class Lambda>
internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn);
Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn);
// Remove all registered benchmarks. All pointers to previously registered
// benchmarks are invalidated.
@@ -1380,7 +1409,7 @@ BENCHMARK_EXPORT void ClearRegisteredBenchmarks();
namespace internal {
// The class used to hold all Benchmarks created from static function.
// (ie those created using the BENCHMARK(...) macros.
class BENCHMARK_EXPORT FunctionBenchmark : public Benchmark {
class BENCHMARK_EXPORT FunctionBenchmark : public benchmark::Benchmark {
public:
FunctionBenchmark(const std::string& name, Function* func)
: Benchmark(name), func_(func) {}
@@ -1392,7 +1421,7 @@ class BENCHMARK_EXPORT FunctionBenchmark : public Benchmark {
};
template <class Lambda>
class LambdaBenchmark : public Benchmark {
class LambdaBenchmark : public benchmark::Benchmark {
public:
void Run(State& st) override { lambda_(st); }
@@ -1406,15 +1435,15 @@ class LambdaBenchmark : public Benchmark {
};
} // namespace internal
inline internal::Benchmark* RegisterBenchmark(const std::string& name,
internal::Function* fn) {
inline Benchmark* RegisterBenchmark(const std::string& name,
internal::Function* fn) {
return internal::RegisterBenchmarkInternal(
::benchmark::internal::make_unique<internal::FunctionBenchmark>(name,
fn));
}
template <class Lambda>
internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) {
Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) {
using BenchType =
internal::LambdaBenchmark<typename std::decay<Lambda>::type>;
return internal::RegisterBenchmarkInternal(
@@ -1423,16 +1452,16 @@ internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn) {
}
template <class Lambda, class... Args>
internal::Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn,
Args&&... args) {
Benchmark* RegisterBenchmark(const std::string& name, Lambda&& fn,
Args&&... args) {
return benchmark::RegisterBenchmark(
name, [=](benchmark::State& st) { fn(st, args...); });
}
// The base class for all fixture tests.
class Fixture : public internal::Benchmark {
class Fixture : public Benchmark {
public:
Fixture() : internal::Benchmark("") {}
Fixture() : Benchmark("") {}
void Run(State& st) override {
this->SetUp(st);
@@ -1455,14 +1484,29 @@ class Fixture : public internal::Benchmark {
// ------------------------------------------------------
// Macro to register benchmarks
// clang-format off
#if defined(__clang__)
#define BENCHMARK_DISABLE_COUNTER_WARNING \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wunknown-warning-option\"") \
_Pragma("GCC diagnostic ignored \"-Wc2y-extensions\"")
#define BENCHMARK_RESTORE_COUNTER_WARNING _Pragma("GCC diagnostic pop")
#else
#define BENCHMARK_DISABLE_COUNTER_WARNING
#define BENCHMARK_RESTORE_COUNTER_WARNING
#endif
// clang-format on
// Check that __COUNTER__ is defined and that __COUNTER__ increases by 1
// every time it is expanded. X + 1 == X + 0 is used in case X is defined to be
// empty. If X is empty the expression becomes (+1 == +0).
BENCHMARK_DISABLE_COUNTER_WARNING
#if defined(__COUNTER__) && (__COUNTER__ + 1 == __COUNTER__ + 0)
#define BENCHMARK_PRIVATE_UNIQUE_ID __COUNTER__
#else
#define BENCHMARK_PRIVATE_UNIQUE_ID __LINE__
#endif
BENCHMARK_RESTORE_COUNTER_WARNING
// Helpers for generating unique variable names
#define BENCHMARK_PRIVATE_NAME(...) \
@@ -1475,17 +1519,19 @@ class Fixture : public internal::Benchmark {
#define BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method) \
BaseClass##_##Method##_Benchmark
#define BENCHMARK_PRIVATE_DECLARE(n) \
/* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \
static ::benchmark::internal::Benchmark const* const BENCHMARK_PRIVATE_NAME( \
n) BENCHMARK_UNUSED
#define BENCHMARK_PRIVATE_DECLARE(n) \
BENCHMARK_DISABLE_COUNTER_WARNING \
/* NOLINTNEXTLINE(misc-use-anonymous-namespace) */ \
static ::benchmark::Benchmark const* const BENCHMARK_PRIVATE_NAME(n) \
BENCHMARK_RESTORE_COUNTER_WARNING BENCHMARK_UNUSED
#define BENCHMARK(...) \
BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
::benchmark::internal::make_unique< \
::benchmark::internal::FunctionBenchmark>(#__VA_ARGS__, \
__VA_ARGS__)))
#define BENCHMARK(...) \
BENCHMARK_PRIVATE_DECLARE(_benchmark_) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
::benchmark::internal::make_unique< \
::benchmark::internal::FunctionBenchmark>( \
#__VA_ARGS__, \
static_cast<::benchmark::internal::Function*>(__VA_ARGS__))))
// Old-style macros
#define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a))
@@ -1526,21 +1572,25 @@ class Fixture : public internal::Benchmark {
BENCHMARK_PRIVATE_DECLARE(n) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
::benchmark::internal::make_unique< \
::benchmark::internal::FunctionBenchmark>(#n "<" #a ">", n<a>)))
::benchmark::internal::FunctionBenchmark>( \
#n "<" #a ">", \
static_cast<::benchmark::internal::Function*>(n<a>))))
#define BENCHMARK_TEMPLATE2(n, a, b) \
BENCHMARK_PRIVATE_DECLARE(n) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
::benchmark::internal::make_unique< \
::benchmark::internal::FunctionBenchmark>(#n "<" #a "," #b ">", \
n<a, b>)))
#define BENCHMARK_TEMPLATE2(n, a, b) \
BENCHMARK_PRIVATE_DECLARE(n) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
::benchmark::internal::make_unique< \
::benchmark::internal::FunctionBenchmark>( \
#n "<" #a "," #b ">", \
static_cast<::benchmark::internal::Function*>(n<a, b>))))
#define BENCHMARK_TEMPLATE(n, ...) \
BENCHMARK_PRIVATE_DECLARE(n) = \
(::benchmark::internal::RegisterBenchmarkInternal( \
::benchmark::internal::make_unique< \
::benchmark::internal::FunctionBenchmark>( \
#n "<" #__VA_ARGS__ ">", n<__VA_ARGS__>)))
#n "<" #__VA_ARGS__ ">", \
static_cast<::benchmark::internal::Function*>(n<__VA_ARGS__>))))
// This will register a benchmark for a templatized function,
// with the additional arguments specified by `...`.
@@ -1661,9 +1711,11 @@ class Fixture : public internal::Benchmark {
::benchmark::internal::make_unique<UniqueName>()))
#define BENCHMARK_TEMPLATE_INSTANTIATE_F(BaseClass, Method, ...) \
BENCHMARK_DISABLE_COUNTER_WARNING \
BENCHMARK_TEMPLATE_PRIVATE_INSTANTIATE_F( \
BaseClass, Method, BENCHMARK_PRIVATE_NAME(BaseClass##Method), \
__VA_ARGS__)
__VA_ARGS__) \
BENCHMARK_RESTORE_COUNTER_WARNING
// This macro will define and register a benchmark within a fixture class.
#define BENCHMARK_F(BaseClass, Method) \
@@ -1798,6 +1850,7 @@ class BENCHMARK_EXPORT BenchmarkReporter {
complexity(oNone),
complexity_lambda(),
complexity_n(0),
statistics(),
report_big_o(false),
report_rms(false),
allocs_per_iter(0.0) {}

View File

@@ -708,11 +708,12 @@ void RegisterProfilerManager(ProfilerManager* manager) {
internal::profiler_manager = manager;
}
void AddCustomContext(const std::string& key, const std::string& value) {
void AddCustomContext(std::string key, std::string value) {
if (internal::global_context == nullptr) {
internal::global_context = new std::map<std::string, std::string>();
}
if (!internal::global_context->emplace(key, value).second) {
if (!internal::global_context->emplace(std::move(key), std::move(value))
.second) {
std::cerr << "Failed to add custom context \"" << key << "\" as it already "
<< "exists with value \"" << value << "\"\n";
}
@@ -722,6 +723,7 @@ namespace internal {
void (*HelperPrintf)();
namespace {
void PrintUsageAndExit() {
HelperPrintf();
std::flush(std::cout);
@@ -810,6 +812,8 @@ void ParseCommandLineFlags(int* argc, char** argv) {
}
}
} // end namespace
int InitializeStreams() {
static std::ios_base::Init init;
return 0;

View File

@@ -7,7 +7,8 @@
namespace benchmark {
namespace internal {
BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx,
BenchmarkInstance::BenchmarkInstance(benchmark::Benchmark* benchmark,
int family_idx,
int per_family_instance_idx,
const std::vector<int64_t>& args,
int thread_count)

View File

@@ -17,7 +17,7 @@ namespace internal {
// Information kept per benchmark we may want to run
class BenchmarkInstance {
public:
BenchmarkInstance(Benchmark* benchmark, int family_idx,
BenchmarkInstance(benchmark::Benchmark* benchmark, int family_idx,
int per_family_instance_idx,
const std::vector<int64_t>& args, int thread_count);
@@ -52,7 +52,7 @@ class BenchmarkInstance {
private:
BenchmarkName name_;
Benchmark& benchmark_;
benchmark::Benchmark& benchmark_;
const int family_index_;
const int per_family_instance_index_;
AggregationReportMode aggregation_report_mode_;

View File

@@ -75,7 +75,7 @@ class BenchmarkFamilies {
static BenchmarkFamilies* GetInstance();
// Registers a benchmark family and returns the index assigned to it.
size_t AddBenchmark(std::unique_ptr<Benchmark> family);
size_t AddBenchmark(std::unique_ptr<benchmark::Benchmark> family);
// Clear all registered benchmark families.
void ClearBenchmarks();
@@ -89,7 +89,7 @@ class BenchmarkFamilies {
private:
BenchmarkFamilies() {}
std::vector<std::unique_ptr<Benchmark>> families_;
std::vector<std::unique_ptr<benchmark::Benchmark>> families_;
Mutex mutex_;
};
@@ -98,7 +98,8 @@ BenchmarkFamilies* BenchmarkFamilies::GetInstance() {
return &instance;
}
size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
size_t BenchmarkFamilies::AddBenchmark(
std::unique_ptr<benchmark::Benchmark> family) {
MutexLock l(mutex_);
size_t index = families_.size();
families_.push_back(std::move(family));
@@ -135,7 +136,7 @@ bool BenchmarkFamilies::FindBenchmarks(
int next_family_index = 0;
MutexLock l(mutex_);
for (std::unique_ptr<Benchmark>& family : families_) {
for (std::unique_ptr<benchmark::Benchmark>& family : families_) {
int family_index = next_family_index;
int per_family_instance_index = 0;
@@ -179,7 +180,7 @@ bool BenchmarkFamilies::FindBenchmarks(
++per_family_instance_index;
// Only bump the next family index once we've estabilished that
// Only bump the next family index once we've established that
// at least one instance of this family will be run.
if (next_family_index == family_index) {
++next_family_index;
@@ -191,8 +192,9 @@ bool BenchmarkFamilies::FindBenchmarks(
return true;
}
Benchmark* RegisterBenchmarkInternal(std::unique_ptr<Benchmark> bench) {
Benchmark* bench_ptr = bench.get();
benchmark::Benchmark* RegisterBenchmarkInternal(
std::unique_ptr<benchmark::Benchmark> bench) {
benchmark::Benchmark* bench_ptr = bench.get();
BenchmarkFamilies* families = BenchmarkFamilies::GetInstance();
families->AddBenchmark(std::move(bench));
return bench_ptr;
@@ -206,13 +208,15 @@ bool FindBenchmarksInternal(const std::string& re,
return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err);
}
} // end namespace internal
//=============================================================================//
// Benchmark
//=============================================================================//
Benchmark::Benchmark(const std::string& name)
: name_(name),
aggregation_report_mode_(ARM_Unspecified),
aggregation_report_mode_(internal::ARM_Unspecified),
time_unit_(GetDefaultTimeUnit()),
use_default_time_unit_(true),
range_multiplier_(kRangeMultiplier),
@@ -253,7 +257,7 @@ Benchmark* Benchmark::Unit(TimeUnit unit) {
Benchmark* Benchmark::Range(int64_t start, int64_t limit) {
BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
std::vector<int64_t> arglist;
AddRange(&arglist, start, limit, range_multiplier_);
internal::AddRange(&arglist, start, limit, range_multiplier_);
for (int64_t i : arglist) {
args_.push_back({i});
@@ -266,8 +270,8 @@ Benchmark* Benchmark::Ranges(
BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges.size()));
std::vector<std::vector<int64_t>> arglists(ranges.size());
for (std::size_t i = 0; i < ranges.size(); i++) {
AddRange(&arglists[i], ranges[i].first, ranges[i].second,
range_multiplier_);
internal::AddRange(&arglists[i], ranges[i].first, ranges[i].second,
range_multiplier_);
}
ArgsProduct(arglists);
@@ -330,7 +334,8 @@ Benchmark* Benchmark::Args(const std::vector<int64_t>& args) {
return this;
}
Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
Benchmark* Benchmark::Apply(
const std::function<void(Benchmark* benchmark)>& custom_arguments) {
custom_arguments(this);
return this;
}
@@ -381,8 +386,8 @@ Benchmark* Benchmark::MinWarmUpTime(double t) {
Benchmark* Benchmark::Iterations(IterationCount n) {
BM_CHECK(n > 0);
BM_CHECK(IsZero(min_time_));
BM_CHECK(IsZero(min_warmup_time_));
BM_CHECK(internal::IsZero(min_time_));
BM_CHECK(internal::IsZero(min_warmup_time_));
iterations_ = n;
return this;
}
@@ -394,21 +399,23 @@ Benchmark* Benchmark::Repetitions(int n) {
}
Benchmark* Benchmark::ReportAggregatesOnly(bool value) {
aggregation_report_mode_ = value ? ARM_ReportAggregatesOnly : ARM_Default;
aggregation_report_mode_ =
value ? internal::ARM_ReportAggregatesOnly : internal::ARM_Default;
return this;
}
Benchmark* Benchmark::DisplayAggregatesOnly(bool value) {
// If we were called, the report mode is no longer 'unspecified', in any case.
using internal::AggregationReportMode;
aggregation_report_mode_ = static_cast<AggregationReportMode>(
aggregation_report_mode_ | ARM_Default);
aggregation_report_mode_ | internal::ARM_Default);
if (value) {
aggregation_report_mode_ = static_cast<AggregationReportMode>(
aggregation_report_mode_ | ARM_DisplayReportAggregatesOnly);
aggregation_report_mode_ | internal::ARM_DisplayReportAggregatesOnly);
} else {
aggregation_report_mode_ = static_cast<AggregationReportMode>(
aggregation_report_mode_ & ~ARM_DisplayReportAggregatesOnly);
aggregation_report_mode_ & ~internal::ARM_DisplayReportAggregatesOnly);
}
return this;
@@ -462,7 +469,7 @@ Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
BM_CHECK_GT(min_threads, 0);
BM_CHECK_GE(max_threads, min_threads);
AddRange(&thread_counts_, min_threads, max_threads, 2);
internal::AddRange(&thread_counts_, min_threads, max_threads, 2);
return this;
}
@@ -514,6 +521,8 @@ TimeUnit Benchmark::GetTimeUnit() const {
return use_default_time_unit_ ? GetDefaultTimeUnit() : time_unit_;
}
namespace internal {
//=============================================================================//
// FunctionBenchmark
//=============================================================================//

View File

@@ -3,6 +3,7 @@
#include <algorithm>
#include <limits>
#include <type_traits>
#include <vector>
#include "check.h"

View File

@@ -123,7 +123,12 @@ BenchmarkReporter::Run CreateRunReport(
: 0;
}
internal::Finish(&report.counters, results.iterations, seconds,
// The CPU time is the total time taken by all thread. If we used that as
// the denominator, we'd be calculating the rate per thread here. This is
// why we have to divide the total cpu_time by the number of threads for
// global counters to get a global rate.
const double thread_seconds = seconds / b.threads();
internal::Finish(&report.counters, results.iterations, thread_seconds,
b.threads());
}
return report;
@@ -191,7 +196,7 @@ class ThreadRunnerDefault : public ThreadRunnerBase {
explicit ThreadRunnerDefault(int num_threads)
: pool(static_cast<size_t>(num_threads - 1)) {}
void RunThreads(const std::function<void(int)>& fn) final {
void RunThreads(const std::function<void(int)>& fn) override final {
// Run all but one thread in separate threads
for (std::size_t ti = 0; ti < pool.size(); ++ti) {
pool[ti] = std::thread(fn, static_cast<int>(ti + 1));
@@ -212,7 +217,8 @@ class ThreadRunnerDefault : public ThreadRunnerBase {
};
std::unique_ptr<ThreadRunnerBase> GetThreadRunner(
const threadrunner_factory& userThreadRunnerFactory, int num_threads) {
const benchmark::threadrunner_factory& userThreadRunnerFactory,
int num_threads) {
return userThreadRunnerFactory
? userThreadRunnerFactory(num_threads)
: std::make_unique<ThreadRunnerDefault>(num_threads);
@@ -400,7 +406,7 @@ bool BenchmarkRunner::ShouldReportIterationResults(
}
double BenchmarkRunner::GetMinTimeToApply() const {
// In order to re-use functionality to run and measure benchmarks for running
// In order to reuse functionality to run and measure benchmarks for running
// a warmup phase of the benchmark, we need a way of telling whether to apply
// min_time or min_warmup_time. This function will figure out if we are in the
// warmup phase and therefore need to apply min_warmup_time or if we already

View File

@@ -5,6 +5,8 @@
#include <iostream>
#include <string>
#include "internal_macros.h"
namespace benchmark {
enum LogColor {
COLOR_DEFAULT,
@@ -17,11 +19,14 @@ enum LogColor {
COLOR_WHITE
};
PRINTF_FORMAT_STRING_FUNC(1, 0)
std::string FormatString(const char* msg, va_list args);
std::string FormatString(const char* msg, ...);
PRINTF_FORMAT_STRING_FUNC(1, 2) std::string FormatString(const char* msg, ...);
PRINTF_FORMAT_STRING_FUNC(3, 0)
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt,
va_list args);
PRINTF_FORMAT_STRING_FUNC(3, 4)
void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...);
// Returns true if stdout appears to be a terminal that supports colored

View File

@@ -179,6 +179,8 @@ std::map<std::string, std::string> KvPairsFromEnv(
return value;
}
namespace {
// Parses a string as a command line flag. The string should have
// the format "--flag=value". When def_optional is true, the "=value"
// part can be omitted.
@@ -217,6 +219,8 @@ const char* ParseFlagValue(const char* str, const char* flag,
return flag_end + 1;
}
} // end namespace
BENCHMARK_EXPORT
bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
// Gets the value of the flag as a string.

View File

@@ -17,7 +17,6 @@
#include "complexity.h"
#include <algorithm>
#include <cmath>
#include "benchmark/benchmark.h"
@@ -25,6 +24,8 @@
namespace benchmark {
namespace {
// Internal function to calculate the different scalability forms
BigOFunc* FittingCurve(BigO complexity) {
switch (complexity) {
@@ -48,6 +49,8 @@ BigOFunc* FittingCurve(BigO complexity) {
}
}
} // end namespace
// Function to return an string for the calculated complexity
std::string GetBigOString(BigO complexity) {
switch (complexity) {
@@ -68,6 +71,8 @@ std::string GetBigOString(BigO complexity) {
}
}
namespace {
// Find the coefficient for the high-order term in the running time, by
// minimizing the sum of squares of relative error, for the fitting curve
// given by the lambda expression.
@@ -152,6 +157,8 @@ LeastSq MinimalLeastSq(const std::vector<ComplexityN>& n,
return best_fit;
}
} // end namespace
std::vector<BenchmarkReporter::Run> ComputeBigO(
const std::vector<BenchmarkReporter::Run>& reports) {
typedef BenchmarkReporter::Run Run;

View File

@@ -97,6 +97,7 @@ void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
}
}
PRINTF_FORMAT_STRING_FUNC(3, 4)
static void IgnoreColorPrint(std::ostream& out, LogColor /*unused*/,
const char* fmt, ...) {
va_list args;

View File

@@ -17,6 +17,8 @@
namespace benchmark {
namespace internal {
namespace {
double Finish(Counter const& c, IterationCount iterations, double cpu_time,
double num_threads) {
double v = c.value;
@@ -39,6 +41,8 @@ double Finish(Counter const& c, IterationCount iterations, double cpu_time,
return v;
}
} // namespace
void Finish(UserCounters* l, IterationCount iterations, double cpu_time,
double num_threads) {
for (auto& c : *l) {

View File

@@ -12,29 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include "benchmark/benchmark.h"
#include "check.h"
#include "complexity.h"
#include "string_util.h"
#include "timers.h"
// File format reference: http://edoceo.com/utilitas/csv-file-format.
namespace benchmark {
namespace {
std::vector<std::string> elements = {
const std::vector<const char*> elements = {
"name", "iterations", "real_time", "cpu_time",
"time_unit", "bytes_per_second", "items_per_second", "label",
"error_occurred", "error_message"};
} // namespace
std::string CsvEscape(const std::string& s) {
std::string tmp;
@@ -51,6 +45,7 @@ std::string CsvEscape(const std::string& s) {
}
return '"' + tmp + '"';
}
} // namespace
BENCHMARK_EXPORT
bool CSVReporter::ReportContext(const Context& context) {

View File

@@ -36,6 +36,9 @@
// declarations of some other intrinsics, breaking compilation.
// Therefore, we simply declare __rdtsc ourselves. See also
// http://connect.microsoft.com/VisualStudio/feedback/details/262047
//
// Note that MSVC defines the x64 preprocessor macros when building
// for Arm64EC, despite it using Arm64 assembly instructions.
#if defined(COMPILER_MSVC) && !defined(_M_IX86) && !defined(_M_ARM64) && \
!defined(_M_ARM64EC)
extern "C" uint64_t __rdtsc();
@@ -79,7 +82,10 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() {
int64_t ret;
__asm__ volatile("rdtsc" : "=A"(ret));
return ret;
#elif defined(__x86_64__) || defined(__amd64__)
// Note that Clang, like MSVC, defines the x64 preprocessor macros when building
// for Arm64EC, despite it using Arm64 assembly instructions.
#elif (defined(__x86_64__) || defined(__amd64__)) && !defined(__arm64ec__)
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return static_cast<int64_t>((high << 32) | low);
@@ -139,7 +145,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() {
struct timespec ts = {0, 0};
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<int64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
#elif defined(__aarch64__)
#elif defined(__aarch64__) || defined(__arm64ec__)
// System timer of ARMv8 runs at a different frequency than the CPU's.
// The frequency is fixed, typically in the range 1-50MHz. It can be
// read at CNTFRQ special register. We assume the OS has set up

View File

@@ -106,6 +106,16 @@
#define BENCHMARK_MAYBE_UNUSED
#endif
#if defined(__GNUC__) || defined(__clang__)
#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) \
__attribute__((format(printf, format_arg, first_idx)))
#elif defined(__MINGW32__)
#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx) \
__attribute__((format(__MINGW_PRINTF_FORMAT, format_arg, first_idx)))
#else
#define PRINTF_FORMAT_STRING_FUNC(format_arg, first_idx)
#endif
// clang-format on
#endif // BENCHMARK_INTERNAL_MACROS_H_

View File

@@ -81,7 +81,9 @@ std::string FormatKV(std::string const& key, bool value) {
std::string FormatKV(std::string const& key, int64_t value) {
std::stringstream ss;
ss << '"' << StrEscape(key) << "\": " << value;
// We really want to just dump the integer as-is,
// without the system locale interfering.
ss << '"' << StrEscape(key) << "\": " << std::to_string(value);
return ss.str();
}

View File

@@ -214,7 +214,7 @@ PerfCounters PerfCounters::Create(
// This should never happen but if it does, we give up on the
// entire batch as recovery would be a mess.
GetErrorLogInstance() << "***WARNING*** Failed to start counters. "
"Claring out all counters.\n";
"Clearing out all counters.\n";
// Close all performance counters
for (int id : counter_ids) {

View File

@@ -15,6 +15,8 @@
#ifndef BENCHMARK_RE_H_
#define BENCHMARK_RE_H_
#include <vector>
#include "internal_macros.h"
// clang-format off

View File

@@ -112,13 +112,14 @@ std::string ToBinaryStringFullySpecified(double value, int precision,
return mantissa + ExponentToPrefix(exponent, one_k == Counter::kIs1024);
}
PRINTF_FORMAT_STRING_FUNC(1, 0)
std::string StrFormatImp(const char* msg, va_list args) {
// we might need a second shot at this, so pre-emptivly make a copy
va_list args_cp;
va_copy(args_cp, args);
// TODO(ericwf): use std::array for first attempt to avoid one memory
// allocation guess what the size might be
// Use std::array for first attempt to avoid one memory allocation guess what
// the size might be
std::array<char, 256> local_buff = {};
// 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation

View File

@@ -463,7 +463,7 @@ std::string GetSystemName() {
DWCOUNT, NULL, 0, NULL, NULL);
str.resize(len);
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, hostname, DWCOUNT, &str[0],
str.size(), NULL, NULL);
static_cast<int>(str.size()), NULL, NULL);
#endif
return str;
#elif defined(BENCHMARK_OS_QURT)

View File

@@ -108,6 +108,10 @@ ext.addTaskToCopyAllOutputs = { task ->
copyAllOutputs.from task.archiveFile
}
ext.makeZipBaseName = { group, artifactId ->
return "_GROUP_${group.replace(".", "_")}_ID_${artifactId}_CLS"
}
subprojects {
apply plugin: 'eclipse'
apply plugin: 'idea'
@@ -120,8 +124,8 @@ subprojects {
plugins.withType(JavaPlugin) {
java {
sourceCompatibility = 21
targetCompatibility = 21
sourceCompatibility = 25
targetCompatibility = 25
}
}
@@ -141,11 +145,13 @@ subprojects {
options.encoding = 'UTF-8'
}
// Enables UTF-8 support in Javadoc
// Enables UTF-8 support in Javadoc, disables 4 MB of fonts being added to every Javadoc JAR, add our styles
tasks.withType(Javadoc) {
options.addStringOption("charset", "utf-8")
options.addStringOption("docencoding", "utf-8")
options.addStringOption("encoding", "utf-8")
options.addBooleanOption("-no-fonts", true)
options.addStringOption("-add-stylesheet", "${rootDir}/docs/javadoc.css")
}
// Sign outputs with Developer ID
@@ -187,5 +193,5 @@ ext.getCurrentArch = {
}
wrapper {
gradleVersion = '9.2.0'
gradleVersion = '9.4.1'
}

View File

@@ -47,9 +47,8 @@ import org.wpilib.vision.stream.CameraServer;
*/
public final class Main {
private static String configFile = "/boot/frc.json";
private static String configFile = "/boot/CameraServerConfig.json";
@SuppressWarnings("MemberName")
public static class CameraConfig {
public String name;
public String path;

View File

@@ -46,9 +46,9 @@
*/
#ifdef __RASPBIAN__
static const char* configFile = "/boot/frc.json";
static const char* configFile = "/boot/CameraServerConfig.json";
#else
static const char* configFile = "frc.json";
static const char* configFile = "CameraServerConfig.json";
#endif
namespace {
@@ -69,8 +69,8 @@ bool ReadCameraConfig(const wpi::util::json& config) {
// name
try {
c.name = config.at("name").get<std::string>();
} catch (const wpi::util::json::exception& e) {
c.name = config.at("name").get_string();
} catch (const std::logic_error& e) {
wpi::util::print(stderr,
"config error in '{}': could not read camera name: {}\n",
configFile, e.what());
@@ -79,8 +79,8 @@ bool ReadCameraConfig(const wpi::util::json& config) {
// path
try {
c.path = config.at("path").get<std::string>();
} catch (const wpi::util::json::exception& e) {
c.path = config.at("path").get_string();
} catch (const std::logic_error& e) {
wpi::util::print(
stderr, "config error in '{}': camera '{}': could not read path: {}\n",
configFile, c.name, e.what());
@@ -103,17 +103,16 @@ bool ReadConfig() {
}
// parse file
wpi::util::json j;
try {
j = wpi::util::json::parse(fileBuffer.value()->GetCharBuffer());
} catch (const wpi::util::json::parse_error& e) {
wpi::util::print(stderr, "config error in '{}': byte {}: {}\n", configFile,
e.byte, e.what());
auto buf = fileBuffer.value()->GetCharBuffer();
auto j = wpi::util::json::parse({buf.data(), buf.size()});
if (!j) {
wpi::util::print(stderr, "config error in '{}': {}\n", configFile,
j.error());
return false;
}
// top level must be an object
if (!j.is_object()) {
if (!j->is_object()) {
wpi::util::print(stderr, "config error in '{}': must be JSON object\n",
configFile);
return false;
@@ -121,8 +120,8 @@ bool ReadConfig() {
// team number
try {
team = j.at("team").get<unsigned int>();
} catch (const wpi::util::json::exception& e) {
team = j->at("team").get_int();
} catch (const std::logic_error& e) {
wpi::util::print(stderr,
"config error in '{}': could not read team number: {}\n",
configFile, e.what());
@@ -130,9 +129,9 @@ bool ReadConfig() {
}
// ntmode (optional)
if (j.count("ntmode") != 0) {
if (auto ntmode = j->lookup("ntmode")) {
try {
auto str = j.at("ntmode").get<std::string>();
auto str = ntmode->get_string();
if (wpi::util::equals_lower(str, "client")) {
server = false;
} else if (wpi::util::equals_lower(str, "server")) {
@@ -143,7 +142,7 @@ bool ReadConfig() {
"config error in '{}': could not understand ntmode value '{}'\n",
configFile, str);
}
} catch (const wpi::util::json::exception& e) {
} catch (const std::logic_error& e) {
wpi::util::print(stderr,
"config error in '{}': could not read ntmode: {}\n",
configFile, e.what());
@@ -152,12 +151,12 @@ bool ReadConfig() {
// cameras
try {
for (auto&& camera : j.at("cameras")) {
for (auto&& camera : j->at("cameras").get_array()) {
if (!ReadCameraConfig(camera)) {
return false;
}
}
} catch (const wpi::util::json::exception& e) {
} catch (const std::logic_error& e) {
wpi::util::print(stderr,
"config error in '{}': could not read cameras: {}\n",
configFile, e.what());

View File

@@ -483,15 +483,15 @@ public final class CameraServer {
/** Provide string description of pixel format. */
private static String pixelFormatToString(PixelFormat pixelFormat) {
return switch (pixelFormat) {
case kMJPEG -> "MJPEG";
case kYUYV -> "YUYV";
case kRGB565 -> "RGB565";
case kBGR -> "BGR";
case kBGRA -> "BGRA";
case kGray -> "Gray";
case kY16 -> "Y16";
case kUYVY -> "UYVY";
case kUnknown -> "Unknown";
case MJPEG -> "MJPEG";
case YUYV -> "YUYV";
case RGB565 -> "RGB565";
case BGR -> "BGR";
case BGRA -> "BGRA";
case GRAY -> "Gray";
case Y16 -> "Y16";
case UYVY -> "UYVY";
case UNKNOWN -> "Unknown";
};
}
@@ -610,7 +610,7 @@ public final class CameraServer {
*/
public static MjpegServer addSwitchedCamera(String name) {
// create a dummy CvSource
CvSource source = new CvSource(name, PixelFormat.kMJPEG, 160, 120, 30);
CvSource source = new CvSource(name, PixelFormat.MJPEG, 160, 120, 30);
MjpegServer server = startAutomaticCapture(source);
synchronized (CameraServer.class) {
m_fixedSources.put(server.getHandle(), source.getHandle());
@@ -725,7 +725,7 @@ public final class CameraServer {
* @return OpenCV source for the MJPEG stream
*/
public static CvSource putVideo(String name, int width, int height) {
CvSource source = new CvSource(name, PixelFormat.kMJPEG, width, height, 30);
CvSource source = new CvSource(name, PixelFormat.MJPEG, width, height, 30);
startAutomaticCapture(source);
return source;
}

View File

@@ -186,7 +186,7 @@ std::vector<std::string> Instance::GetSourceStreamValues(CS_Source source) {
value = "mjpg:" + value;
}
#ifdef __FRC_SYSTEMCORE__
#ifdef __FIRST_SYSTEMCORE__
// Look to see if we have a passthrough server for this source
// Only do this on the systemcore
for (const auto& i : m_sinks) {
@@ -251,15 +251,15 @@ void Instance::UpdateStreamValues() {
static std::string PixelFormatToString(wpi::util::PixelFormat pixelFormat) {
switch (pixelFormat) {
case wpi::util::PixelFormat::kMJPEG:
case wpi::util::PixelFormat::MJPEG:
return "MJPEG";
case wpi::util::PixelFormat::kYUYV:
case wpi::util::PixelFormat::YUYV:
return "YUYV";
case wpi::util::PixelFormat::kRGB565:
case wpi::util::PixelFormat::RGB565:
return "RGB565";
case wpi::util::PixelFormat::kBGR:
case wpi::util::PixelFormat::BGR:
return "BGR";
case wpi::util::PixelFormat::kGray:
case wpi::util::PixelFormat::GRAY:
return "Gray";
default:
return "Unknown";
@@ -508,7 +508,7 @@ cs::UsbCamera CameraServer::StartAutomaticCapture(std::string_view name,
cs::MjpegServer CameraServer::AddSwitchedCamera(std::string_view name) {
auto& inst = ::GetInstance();
// create a dummy CvSource
cs::CvSource source{name, wpi::util::PixelFormat::kMJPEG, 160, 120, 30};
cs::CvSource source{name, wpi::util::PixelFormat::MJPEG, 160, 120, 30};
cs::MjpegServer server = StartAutomaticCapture(source);
inst.m_fixedSources[server.GetHandle()] = source.GetHandle();
@@ -632,7 +632,7 @@ cs::CvSink CameraServer::GetVideo(std::string_view name,
cs::CvSource CameraServer::PutVideo(std::string_view name, int width,
int height) {
::GetInstance();
cs::CvSource source{name, wpi::util::PixelFormat::kMJPEG, width, height, 30};
cs::CvSource source{name, wpi::util::PixelFormat::MJPEG, width, height, 30};
StartAutomaticCapture(source);
return source;
}

View File

@@ -24,8 +24,7 @@ macro(add_doxygen_docs)
set(DOXYGEN_WARN_AS_ERROR "FAIL_ON_WARNINGS_PRINT")
list(FILTER dirs EXCLUDE REGEX fmt|memory|units)
list(
APPEND
DOXYGEN_EXCLUDE_PATTERNS
APPEND DOXYGEN_EXCLUDE_PATTERNS
# apriltag
"apriltag_pose.h"
# llvm

View File

@@ -63,5 +63,6 @@ macro(wpilib_target_warnings target)
AND ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU"
)
target_compile_options(${target} PRIVATE -gz=zlib)
target_link_options(${target} PRIVATE -gz=zlib)
endif()
endmacro()

View File

@@ -6,8 +6,7 @@ macro(add_source_jar target)
# Find all packages
foreach(directory ${directories})
cmake_path(
RELATIVE_PATH
directory
RELATIVE_PATH directory
BASE_DIRECTORY ${base_package_dir}
OUTPUT_VARIABLE package_name
)

View File

@@ -8,8 +8,7 @@ string(REGEX REPLACE "[^a-zA-Z0-9]" "_" funcName "${inputBase}")
set(funcName "GetResource_${funcName}")
file(
WRITE
"${output}"
WRITE "${output}"
"#include <stddef.h>\n#include <string_view>\nextern \"C\" {\nstatic const unsigned char contents[] = {"
)
@@ -17,8 +16,7 @@ string(REGEX MATCHALL ".." outputData "${fileHex}")
string(REGEX REPLACE ";" ", 0x" outputData "${outputData}")
file(APPEND "${output}" " 0x${outputData} };\n")
file(
APPEND
"${output}"
APPEND "${output}"
"const unsigned char* ${prefix}${funcName}(size_t* len) {\n *len = ${fileSize};\n return contents;\n}\n}\n"
)
@@ -26,8 +24,7 @@ if(NOT namespace STREQUAL "")
file(APPEND "${output}" "namespace ${namespace} {\n")
endif()
file(
APPEND
"${output}"
APPEND "${output}"
"std::string_view ${funcName}() {\n return std::string_view(reinterpret_cast<const char*>(contents), ${fileSize});\n}\n"
)
if(NOT namespace STREQUAL "")

View File

@@ -43,6 +43,7 @@ generate_wpilib_new_commands(
write_source_files(
name = "write_wpilib_new_commands",
diff_args = ["-u"],
files = {
"src/generated": ":generate_wpilib_new_commands",
},

View File

@@ -8,14 +8,14 @@ if(WITH_JAVA)
include(UseJava)
file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java src/generated/main/java/*.java)
file(GLOB JACKSON_JARS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson/*.jar")
file(GLOB AVAJE_JARS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/avaje/*.jar")
add_jar(
commandsv2_jar
${JAVA_SOURCES}
INCLUDE_JARS
hal_jar
ntcore_jar
${JACKSON_JARS}
${AVAJE_JARS}
cscore_jar
cameraserver_jar
wpimath_jar
@@ -62,7 +62,7 @@ add_library(commandsv2 ${commandsv2_native_src})
set_target_properties(commandsv2 PROPERTIES DEBUG_POSTFIX "d")
set_property(TARGET commandsv2 PROPERTY FOLDER "libraries")
target_compile_features(commandsv2 PUBLIC cxx_std_20)
target_compile_features(commandsv2 PUBLIC cxx_std_23)
wpilib_target_warnings(commandsv2)
target_link_libraries(commandsv2 wpilibc)

View File

@@ -3,7 +3,7 @@
"name": "Commands V2",
"version": "1.0.0",
"uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266",
"frcYear": "2027_alpha1",
"wpilibYear": "2027_alpha5",
"mavenUrls": [],
"jsonUrl": "",
"conflictsWith": [

View File

@@ -26,7 +26,7 @@ import org.wpilib.util.sendable.SendableRegistry;
* <p>Commands are run synchronously from the main robot loop; no multithreading is used, unless
* specified explicitly from the command implementation.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
@NoDiscard("Commands must be used! Did you mean to bind it to a trigger?")
public abstract class Command implements Sendable {
@@ -307,26 +307,6 @@ public abstract class Command implements Sendable {
return new ParallelDeadlineGroup(deadline, this);
}
/**
* Decorates this command with a set of commands to run parallel to it, ending when the calling
* command ends and interrupting all the others. Often more convenient/less-verbose than
* constructing a new {@link ParallelDeadlineGroup} explicitly.
*
* <p>Note: This decorator works by adding this command to a composition. The command the
* decorator was called on cannot be scheduled independently or be added to a different
* composition (namely, decorators), unless it is manually cleared from the list of composed
* commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
* returned from this method can be further decorated without issue.
*
* @param parallel the commands to run in parallel
* @return the decorated command
* @deprecated Use {@link deadlineFor} instead.
*/
@Deprecated(since = "2025", forRemoval = true)
public ParallelDeadlineGroup deadlineWith(Command... parallel) {
return new ParallelDeadlineGroup(this, parallel);
}
/**
* Decorates this command with a set of commands to run parallel to it, ending when the calling
* command ends and interrupting all the others. Often more convenient/less-verbose than
@@ -535,16 +515,6 @@ public abstract class Command implements Sendable {
});
}
/**
* Schedules this command.
*
* @deprecated Use CommandScheduler.getInstance().schedule(Command...) instead
*/
@Deprecated(since = "2025", forRemoval = true)
public void schedule() {
CommandScheduler.getInstance().schedule(this);
}
/**
* Cancels this command. Will call {@link #end(boolean) end(true)}. Commands will be canceled
* regardless of {@link InterruptionBehavior interruption behavior}.

View File

@@ -23,7 +23,8 @@ import java.util.WeakHashMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.wpilib.command2.Command.InterruptionBehavior;
import org.wpilib.driverstation.DriverStation;
import org.wpilib.driverstation.DriverStationErrors;
import org.wpilib.driverstation.RobotState;
import org.wpilib.event.EventLoop;
import org.wpilib.framework.RobotBase;
import org.wpilib.framework.TimedRobot;
@@ -40,7 +41,7 @@ import org.wpilib.util.sendable.SendableRegistry;
* CommandScheduler#registerSubsystem(Subsystem...)} in order for their {@link Subsystem#periodic()}
* methods to be called and for their default commands to be scheduled.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public final class CommandScheduler implements Sendable, AutoCloseable {
/** The Singleton Instance. */
@@ -93,7 +94,7 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
private final List<Optional<Command>> m_toCancelInterruptors = new ArrayList<>();
private final Set<Command> m_endingCommands = new LinkedHashSet<>();
private final Watchdog m_watchdog = new Watchdog(TimedRobot.kDefaultPeriod, () -> {});
private final Watchdog m_watchdog = new Watchdog(TimedRobot.DEFAULT_PERIOD, () -> {});
CommandScheduler() {
HAL.reportUsage("CommandScheduler", "");
@@ -175,7 +176,7 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
*/
private void schedule(Command command) {
if (command == null) {
DriverStation.reportWarning("Tried to schedule a null command", true);
DriverStationErrors.reportWarning("Tried to schedule a null command", true);
return;
}
if (m_inRunLoop) {
@@ -189,7 +190,7 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
// run when disabled, or the command is already scheduled.
if (m_disabled
|| isScheduled(command)
|| DriverStation.isDisabled() && !command.runsWhenDisabled()) {
|| RobotState.isDisabled() && !command.runsWhenDisabled()) {
return;
}
@@ -269,7 +270,7 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
m_watchdog.addEpoch("buttons.run()");
m_inRunLoop = true;
boolean isDisabled = DriverStation.isDisabled();
boolean isDisabled = RobotState.isDisabled();
// Run scheduled commands, remove finished commands.
for (Iterator<Command> iterator = m_scheduledCommands.iterator(); iterator.hasNext(); ) {
Command command = iterator.next();
@@ -337,11 +338,12 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
public void registerSubsystem(Subsystem... subsystems) {
for (Subsystem subsystem : subsystems) {
if (subsystem == null) {
DriverStation.reportWarning("Tried to register a null subsystem", true);
DriverStationErrors.reportWarning("Tried to register a null subsystem", true);
continue;
}
if (m_subsystems.containsKey(subsystem)) {
DriverStation.reportWarning("Tried to register an already-registered subsystem", true);
DriverStationErrors.reportWarning(
"Tried to register an already-registered subsystem", true);
continue;
}
m_subsystems.put(subsystem, null);
@@ -379,11 +381,12 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
*/
public void setDefaultCommand(Subsystem subsystem, Command defaultCommand) {
if (subsystem == null) {
DriverStation.reportWarning("Tried to set a default command for a null subsystem", true);
DriverStationErrors.reportWarning(
"Tried to set a default command for a null subsystem", true);
return;
}
if (defaultCommand == null) {
DriverStation.reportWarning("Tried to set a null default command", true);
DriverStationErrors.reportWarning("Tried to set a null default command", true);
return;
}
@@ -394,7 +397,7 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
}
if (defaultCommand.getInterruptionBehavior() == InterruptionBehavior.kCancelIncoming) {
DriverStation.reportWarning(
DriverStationErrors.reportWarning(
"Registering a non-interruptible default command!\n"
+ "This will likely prevent any other commands from requiring this subsystem.",
true);
@@ -413,7 +416,8 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
*/
public void removeDefaultCommand(Subsystem subsystem) {
if (subsystem == null) {
DriverStation.reportWarning("Tried to remove a default command for a null subsystem", true);
DriverStationErrors.reportWarning(
"Tried to remove a default command for a null subsystem", true);
return;
}
@@ -458,7 +462,7 @@ public final class CommandScheduler implements Sendable, AutoCloseable {
*/
private void cancel(Command command, Optional<Command> interruptor) {
if (command == null) {
DriverStation.reportWarning("Tried to cancel a null command", true);
DriverStationErrors.reportWarning("Tried to cancel a null command", true);
return;
}
if (m_endingCommands.contains(command)) {

View File

@@ -17,7 +17,7 @@ import org.wpilib.util.sendable.SendableBuilder;
* added to any other composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class ConditionalCommand extends Command {
private final Command m_onTrue;

View File

@@ -18,7 +18,7 @@ import org.wpilib.util.sendable.SendableBuilder;
* <p>Note that the supplier <i>must</i> create a new Command each call. For selecting one of a
* preallocated set of commands, use {@link SelectCommand}.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class DeferredCommand extends Command {
private final Command m_nullCommand =

View File

@@ -15,7 +15,7 @@ import java.util.function.Consumer;
* command is beyond a certain complexity it is usually better practice to write a proper class for
* it than to inline it.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class FunctionalCommand extends Command {
private final Runnable m_onInit;

View File

@@ -9,7 +9,7 @@ package org.wpilib.command2;
* the scheduler. Users can either pass in a Runnable and a set of requirements, or else subclass
* this command if desired.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class InstantCommand extends FunctionalCommand {
/**

View File

@@ -15,7 +15,7 @@ import org.wpilib.system.Notifier;
* code thread-safe. If you do not know what "thread-safe" means, that is a good sign that you
* should not use this class.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class NotifierCommand extends Command {
private final Notifier m_notifier;

View File

@@ -15,7 +15,7 @@ import java.util.Map;
* added to any other composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class ParallelCommandGroup extends Command {
// maps commands in this composition to whether they are still running

View File

@@ -18,7 +18,7 @@ import org.wpilib.util.sendable.SendableBuilder;
* added to any other composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class ParallelDeadlineGroup extends Command {
// maps commands in this composition to whether they are still running

View File

@@ -16,7 +16,7 @@ import java.util.Set;
* added to any other composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class ParallelRaceGroup extends Command {
// LinkedHashSet guarantees we iterate over commands in the order they were added

View File

@@ -7,7 +7,7 @@ package org.wpilib.command2;
/**
* A command that prints a string when initialized.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class PrintCommand extends InstantCommand {
/**

View File

@@ -18,30 +18,12 @@ import org.wpilib.util.sendable.SendableBuilder;
* from a subsystem already required by the composition, or else the composition will cancel itself
* when the proxy is reached. If this command is interrupted, it will cancel the command.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class ProxyCommand extends Command {
private final Supplier<Command> m_supplier;
private Command m_command;
/**
* Creates a new ProxyCommand that schedules the supplied command when initialized, and ends when
* it is no longer scheduled. Use this for lazily creating <strong>proxied</strong> commands at
* runtime. Proxying should only be done to escape from composition requirement semantics, so if
* only initialization time command construction is needed, use {@link DeferredCommand} instead.
*
* @param supplier the command supplier
* @deprecated This constructor's similarity to {@link DeferredCommand} is confusing and opens
* potential footguns for users who do not fully understand the semantics and implications of
* proxying, but who simply want runtime construction. Users who do know what they are doing
* and need a supplier-constructed proxied command should instead defer a proxy command.
* @see DeferredCommand
*/
@Deprecated(since = "2025", forRemoval = true)
public ProxyCommand(Supplier<Command> supplier) {
m_supplier = requireNonNullParam(supplier, "supplier", "ProxyCommand");
}
/**
* Creates a new ProxyCommand that schedules the given command when initialized, and ends when it
* is no longer scheduled.

View File

@@ -17,7 +17,7 @@ import org.wpilib.util.sendable.SendableBuilder;
* added to any other composition or scheduled individually,and the composition requires all
* subsystems its components require.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class RepeatCommand extends Command {
private final Command m_command;

View File

@@ -11,7 +11,7 @@ import java.util.function.BooleanSupplier;
* use {@link Command#withTimeout(double)} or {@link Command#until(BooleanSupplier)} to give it one.
* If you only wish to execute a Runnable once, use {@link InstantCommand}.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class RunCommand extends FunctionalCommand {
/**

View File

@@ -11,7 +11,7 @@ import java.util.Set;
* CommandGroups. Note that if run from a composition, the composition will not know about the
* status of the scheduled commands, and will treat this command as finishing instantly.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class ScheduleCommand extends Command {
private final Set<Command> m_toSchedule;

View File

@@ -18,7 +18,7 @@ import org.wpilib.util.sendable.SendableBuilder;
* added to any other composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*
* @param <K> The type of key used to select the command
*/

View File

@@ -15,7 +15,7 @@ import org.wpilib.util.sendable.SendableBuilder;
* added to any other composition or scheduled individually, and the composition requires all
* subsystems its components require.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class SequentialCommandGroup extends Command {
private final List<Command> m_commands = new ArrayList<>();
@@ -39,7 +39,6 @@ public class SequentialCommandGroup extends Command {
*
* @param commands Commands to add, in order of execution.
*/
@SuppressWarnings("PMD.UseArraysAsList")
public final void addCommands(Command... commands) {
if (m_currentCommandIndex != -1) {
throw new IllegalStateException(

View File

@@ -14,7 +14,7 @@ import java.util.function.Consumer;
* end condition as-is; either subclass it or use {@link Command#withTimeout(double)} or {@link
* Command#until(java.util.function.BooleanSupplier)} to give it one.
*
* <p>This class is provided by the NewCommands VendorDep
* <p>This class is provided by the Commands v2 VendorDep
*/
public class StartEndCommand extends FunctionalCommand {
/**

Some files were not shown because too many files have changed in this diff Show More