mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-24 01:31:46 +00:00
Compare commits
177 Commits
v2025.1.1-
...
v2025.3.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1efaaefd78 | ||
|
|
71b6e8ec58 | ||
|
|
1a835fec01 | ||
|
|
0ad595c33c | ||
|
|
93bf6c70ba | ||
|
|
a7ae22d764 | ||
|
|
822457d45b | ||
|
|
75321f1d84 | ||
|
|
cd6fee7fea | ||
|
|
517344fe80 | ||
|
|
b0e588fd49 | ||
|
|
0f0e93722e | ||
|
|
f9307de04c | ||
|
|
15dcdebe21 | ||
|
|
0c3c2c1fda | ||
|
|
c898853b4d | ||
|
|
bd2211119f | ||
|
|
13626063dc | ||
|
|
7e6077c546 | ||
|
|
4d126b158c | ||
|
|
e22f76ce73 | ||
|
|
e648b9c86d | ||
|
|
23658a8c62 | ||
|
|
155b3d45e7 | ||
|
|
d62ab12855 | ||
|
|
1921d7b79a | ||
|
|
9dbb0c8c3d | ||
|
|
b2584c6bdf | ||
|
|
53df127535 | ||
|
|
d2611d4ad5 | ||
|
|
b60b2b64bd | ||
|
|
a0976a1fd9 | ||
|
|
b3b515e1dd | ||
|
|
296986397b | ||
|
|
18321e5551 | ||
|
|
b31fd17d05 | ||
|
|
b44a80c07a | ||
|
|
25d11524e8 | ||
|
|
d86a2ec83b | ||
|
|
0690d3d832 | ||
|
|
304b98c0c9 | ||
|
|
72541c10e6 | ||
|
|
00445f4f27 | ||
|
|
8fc3767b30 | ||
|
|
5ab0409c15 | ||
|
|
4caa16e254 | ||
|
|
e52f400687 | ||
|
|
a9f3fc6b2c | ||
|
|
a14545102f | ||
|
|
25e6549398 | ||
|
|
cd92b07321 | ||
|
|
fc9e413ce1 | ||
|
|
007526089e | ||
|
|
c5f7a2b4ac | ||
|
|
638d265b33 | ||
|
|
6125227836 | ||
|
|
e37c35746a | ||
|
|
995bc98ccf | ||
|
|
2de03c9601 | ||
|
|
8e459a4f2a | ||
|
|
58d7c07343 | ||
|
|
9b08f0244c | ||
|
|
7032de3d5d | ||
|
|
159e18ce05 | ||
|
|
257d0e0824 | ||
|
|
b65f159c3f | ||
|
|
11a0c36737 | ||
|
|
17a03514ba | ||
|
|
9ebc4b32ae | ||
|
|
ce60bd5035 | ||
|
|
468a3c6d95 | ||
|
|
4350ea769c | ||
|
|
83397392f4 | ||
|
|
786d22049b | ||
|
|
86137c49f5 | ||
|
|
4edf52d3b6 | ||
|
|
a41fb460a9 | ||
|
|
d4985b8ba0 | ||
|
|
1538370034 | ||
|
|
eef1bf33de | ||
|
|
78b6d61e88 | ||
|
|
e7dd5dca82 | ||
|
|
a27df8ec24 | ||
|
|
85507a6c65 | ||
|
|
b74f84f876 | ||
|
|
54e9c76e03 | ||
|
|
203487a6aa | ||
|
|
57344ef3b2 | ||
|
|
46d401553e | ||
|
|
9e63dcfb16 | ||
|
|
934bf7bf05 | ||
|
|
fe49cbe429 | ||
|
|
0470e51569 | ||
|
|
72fdca3507 | ||
|
|
dee50bf500 | ||
|
|
939a9ceee1 | ||
|
|
b670a59b5b | ||
|
|
9b12ddb595 | ||
|
|
76625fa0f9 | ||
|
|
bb130b67b8 | ||
|
|
469bb3290d | ||
|
|
02a0adc653 | ||
|
|
0c99073b94 | ||
|
|
d631fa8e4b | ||
|
|
19d385d149 | ||
|
|
d0cc7e4eca | ||
|
|
807dffed35 | ||
|
|
f46c81cfe3 | ||
|
|
9ccd73108b | ||
|
|
38d8929f48 | ||
|
|
cc73236a06 | ||
|
|
f8720a628c | ||
|
|
156bd71fef | ||
|
|
6e44187ff6 | ||
|
|
e2cbdf9718 | ||
|
|
66cce1835c | ||
|
|
6fe5da7289 | ||
|
|
80c391e182 | ||
|
|
70f36cce7e | ||
|
|
564c1f2de2 | ||
|
|
a1b642a402 | ||
|
|
f9b3efb712 | ||
|
|
782459dff4 | ||
|
|
4bca79b9af | ||
|
|
68285dae77 | ||
|
|
5e3dba672a | ||
|
|
e943424609 | ||
|
|
4225b732fd | ||
|
|
39d05ebe7c | ||
|
|
cc41a0ed24 | ||
|
|
d5edb4060d | ||
|
|
e08fdeba21 | ||
|
|
544553a58f | ||
|
|
838c5fbcd7 | ||
|
|
38a239b531 | ||
|
|
9a1b4245fa | ||
|
|
e222efaa01 | ||
|
|
f772bb141d | ||
|
|
278efa6384 | ||
|
|
e876452967 | ||
|
|
5c95966d44 | ||
|
|
882233bede | ||
|
|
1921d019b7 | ||
|
|
c3fc7c829d | ||
|
|
4ce8930342 | ||
|
|
60198c0bec | ||
|
|
54f0e11fc0 | ||
|
|
de82ed434d | ||
|
|
4dd3a36d2e | ||
|
|
92f8c89267 | ||
|
|
1eecaaf337 | ||
|
|
892e062316 | ||
|
|
9807d60566 | ||
|
|
c387a7ecae | ||
|
|
715cbb6b76 | ||
|
|
9d40b993f8 | ||
|
|
92ee5bc523 | ||
|
|
5012ad7499 | ||
|
|
145450b73d | ||
|
|
b91864a5ec | ||
|
|
0941251375 | ||
|
|
7d178615fa | ||
|
|
806d56e564 | ||
|
|
65f3345407 | ||
|
|
5e1c6a84ce | ||
|
|
a0af0fd572 | ||
|
|
f377a9c573 | ||
|
|
62338c7287 | ||
|
|
49e3e4a0be | ||
|
|
59dbfc9c2d | ||
|
|
9607c6c10d | ||
|
|
6ef5b85758 | ||
|
|
b6de7acbdb | ||
|
|
fe28fa1ded | ||
|
|
b7eb9fb8f9 | ||
|
|
1d58c5025e | ||
|
|
b4a8d33486 |
6
.bazelrc
6
.bazelrc
@@ -16,9 +16,15 @@ import shared/bazel/compiler_flags/base_linux_flags.rc
|
||||
import shared/bazel/compiler_flags/linux_flags.rc
|
||||
import shared/bazel/compiler_flags/osx_flags.rc
|
||||
import shared/bazel/compiler_flags/roborio_flags.rc
|
||||
import shared/bazel/compiler_flags/systemcore_flags.rc
|
||||
import shared/bazel/compiler_flags/windows_flags.rc
|
||||
import shared/bazel/compiler_flags/coverage_flags.rc
|
||||
|
||||
# Alias toolchain names to what wpilibsuite uses for CI/Artifact naming
|
||||
build:athena --config=roborio
|
||||
build:linuxarm32 --config=raspibookworm32
|
||||
build:linuxarm64 --config=bookworm64
|
||||
|
||||
build:build_java --test_tag_filters=allwpilib-build-java --build_tag_filters=allwpilib-build-java
|
||||
build:build_cpp --test_tag_filters=+allwpilib-build-cpp --build_tag_filters=+allwpilib-build-cpp
|
||||
build:no_example --test_tag_filters=-wpi-example --build_tag_filters=-wpi-example
|
||||
|
||||
65
.github/actions/pregen/action.yml
vendored
Normal file
65
.github/actions/pregen/action.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
name: 'Setup and run pregeneration'
|
||||
description: 'Sets up the dependencies needed to generate generated files and runs all generation scripts'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install jinja and protobuf
|
||||
run: python -m pip install jinja2 protobuf grpcio-tools
|
||||
shell: bash
|
||||
- name: Install protobuf and perl dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y protobuf-compiler liblist-moreutils-perl
|
||||
wget https://github.com/HebiRobotics/QuickBuffers/releases/download/1.3.3/protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
chmod +x protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
shell: bash
|
||||
- name: Regenerate hal
|
||||
run: ./hal/generate_usage_reporting.py
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate ntcore
|
||||
run: ./ntcore/generate_topics.py
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate imgui
|
||||
run: |
|
||||
./thirdparty/imgui_suite/generate_fonts.sh
|
||||
./thirdparty/imgui_suite/generate_gl3w.py
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate HIDs
|
||||
run: |
|
||||
./wpilibc/generate_hids.py
|
||||
./wpilibj/generate_hids.py
|
||||
./wpilibNewCommands/generate_hids.py
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate PWM motor controllers
|
||||
run: |
|
||||
./wpilibc/generate_pwm_motor_controllers.py
|
||||
./wpilibj/generate_pwm_motor_controllers.py
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate mrcal minimath
|
||||
run: ./wpical/generate_mrcal.py
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate wpimath
|
||||
run: |
|
||||
./wpimath/generate_nanopb.py
|
||||
./wpimath/generate_numbers.py
|
||||
./wpimath/generate_quickbuf.py --quickbuf_plugin protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate wpiunits
|
||||
run: ./wpiunits/generate_units.py
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate wpiutil nanopb
|
||||
run: ./wpiutil/generate_nanopb.py
|
||||
shell: bash
|
||||
65
.github/labeler.yml
vendored
Normal file
65
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
'2027':
|
||||
- base-branch: '2027'
|
||||
'component: apriltag':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: apriltag/**
|
||||
'component: command-based':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpilibNewCommands/**
|
||||
'component: cscore':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: cscore/**
|
||||
'component: datalogtool':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: datalogtool/**
|
||||
'component: epilogue':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: epilogue-*/**
|
||||
'component: examples':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpilib*Examples/**
|
||||
'component: glass':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: glass/**
|
||||
'component: hal':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: hal/**
|
||||
'component: ntcore':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ntcore/**
|
||||
'component: outlineviewer':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: outlineviewer/**
|
||||
'component: sysid':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: sysid/**
|
||||
'component: teamnumbersetter':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: roborioteamnumbersetter/**
|
||||
'component: wpilibc':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpilibc/**
|
||||
'component: wpilibj':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpilibj/**
|
||||
'component: wpimath':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpimath/**
|
||||
'component: wpinet':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpinet/**
|
||||
'component: wpiunits':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpiunits/**
|
||||
'component: wpiutil':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpiutil/**
|
||||
'component: wpical':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpical/**
|
||||
'component: usage reporting':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: hal/src/generate/**
|
||||
'attn: NI':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: hal/src/generate/**
|
||||
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"aql": {
|
||||
"items.find": {
|
||||
"repo": "wpilib-mvn-development",
|
||||
"repo": "wpilib-mvn-development-local",
|
||||
"path": { "$nmatch":"*edu/wpi/first/thirdparty*" },
|
||||
"$or":[
|
||||
{
|
||||
|
||||
2
.github/workflows/cmake.yml
vendored
2
.github/workflows/cmake.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
name: Linux
|
||||
container: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
container: wpilib/roborio-cross-ubuntu:2025-22.04
|
||||
flags: "--preset with-java-and-sccache -DCMAKE_BUILD_TYPE=Release -DWITH_EXAMPLES=ON"
|
||||
- os: macOS-14
|
||||
name: macOS
|
||||
|
||||
101
.github/workflows/comment-command.yml
vendored
101
.github/workflows/comment-command.yml
vendored
@@ -1,101 +0,0 @@
|
||||
name: Comment Commands
|
||||
on:
|
||||
issue_comment:
|
||||
types: [ created ]
|
||||
|
||||
jobs:
|
||||
format:
|
||||
if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/format')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: React Rocket
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.issue
|
||||
github.rest.reactions.createForIssueComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: context.payload.comment.id,
|
||||
content: "rocket",
|
||||
});
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.COMMENT_COMMAND_PAT_TOKEN }}
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git checkout -b pr
|
||||
git branch -f main origin/main
|
||||
- name: Checkout PR
|
||||
run: |
|
||||
gh pr checkout $NUMBER
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.COMMENT_COMMAND_PAT_TOKEN }}"
|
||||
NUMBER: ${{ github.event.issue.number }}
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat==2024.45
|
||||
- name: Run wpiformat
|
||||
run: wpiformat
|
||||
- name: Run spotlessApply
|
||||
run: ./gradlew spotlessApply
|
||||
- name: Commit
|
||||
run: |
|
||||
# Set credentials
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
# Commit
|
||||
git commit -am "Formatting fixes"
|
||||
git push
|
||||
|
||||
pregen:
|
||||
if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/pregen')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: React Rocket
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.issue
|
||||
github.rest.reactions.createForIssueComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: context.payload.comment.id,
|
||||
content: "rocket",
|
||||
});
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.COMMENT_COMMAND_PAT_TOKEN }}
|
||||
- name: Checkout PR
|
||||
run: |
|
||||
gh pr checkout $NUMBER
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.COMMENT_COMMAND_PAT_TOKEN }}"
|
||||
NUMBER: ${{ github.event.issue.number }}
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
- name: Install protobuf dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler && wget https://github.com/HebiRobotics/QuickBuffers/releases/download/1.3.3/protoc-gen-quickbuf-1.3.3-linux-x86_64.exe && chmod +x protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
- name: Regenerate all
|
||||
run: ./.github/workflows/pregen_all.py --quickbuf_plugin=protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
- name: Commit
|
||||
run: |
|
||||
# Set credentials
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
# Commit
|
||||
git commit -am "Regenerate pregenerated files"
|
||||
git push
|
||||
7
.github/workflows/documentation.yml
vendored
7
.github/workflows/documentation.yml
vendored
@@ -13,13 +13,14 @@ jobs:
|
||||
publish:
|
||||
name: "Documentation - Publish"
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.repository == 'wpilibsuite/allwpilib' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
if: github.repository == 'wpilibsuite/allwpilib' && (github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
concurrency: ci-docs-publish
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
@@ -32,12 +33,12 @@ jobs:
|
||||
run: |
|
||||
echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
echo "BRANCH=beta" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
- name: Set environment variables (Release)
|
||||
run: |
|
||||
echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
echo "BRANCH=release" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta')
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta') && !contains(github.ref, '2027')
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew docs:generateJavaDocs docs:doxygen -PbuildServer ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
- name: Install SSH Client 🔑
|
||||
|
||||
5
.github/workflows/fix_compile_commands.py
vendored
5
.github/workflows/fix_compile_commands.py
vendored
@@ -18,9 +18,9 @@ def main():
|
||||
for obj in data:
|
||||
out_args = []
|
||||
|
||||
# Filter out -isystem flags that cause false positives
|
||||
iter_args = iter(obj["arguments"])
|
||||
for arg in iter_args:
|
||||
# Filter out -isystem flags that cause false positives
|
||||
if arg == "-isystem":
|
||||
next_arg = next(iter_args)
|
||||
|
||||
@@ -28,6 +28,9 @@ def main():
|
||||
# error: conflicting types for '_mm_prefetch' [clang-diagnostic-error]
|
||||
if not next_arg.startswith("/usr/lib/gcc/"):
|
||||
out_args += ["-isystem", next_arg]
|
||||
# Replace GCC warning argument with one Clang recognizes
|
||||
elif arg == "-Wno-maybe-uninitialized":
|
||||
out_args.append("-Wno-uninitialized")
|
||||
else:
|
||||
out_args.append(arg)
|
||||
|
||||
|
||||
14
.github/workflows/gradle-wrapper-validation.yml
vendored
14
.github/workflows/gradle-wrapper-validation.yml
vendored
@@ -1,14 +0,0 @@
|
||||
name: "Validate Gradle Wrapper"
|
||||
on: [pull_request, push]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@v3
|
||||
55
.github/workflows/gradle.yml
vendored
55
.github/workflows/gradle.yml
vendored
@@ -7,18 +7,25 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
|
||||
build-docker:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- container: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
- container: wpilib/roborio-cross-ubuntu:2025-22.04
|
||||
artifact-name: Athena
|
||||
build-options: "-Ponlylinuxathena"
|
||||
- container: wpilib/raspbian-cross-ubuntu:bullseye-22.04
|
||||
- container: wpilib/raspbian-cross-ubuntu:bookworm-22.04
|
||||
artifact-name: Arm32
|
||||
build-options: "-Ponlylinuxarm32"
|
||||
- container: wpilib/aarch64-cross-ubuntu:bullseye-22.04
|
||||
- container: wpilib/aarch64-cross-ubuntu:bookworm-22.04
|
||||
artifact-name: Arm64
|
||||
build-options: "-Ponlylinuxarm64"
|
||||
- container: wpilib/ubuntu-base:22.04
|
||||
@@ -26,6 +33,7 @@ jobs:
|
||||
build-options: "-Ponlylinuxx86-64"
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
- name: Free Disk Space
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
@@ -42,7 +50,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
- name: Build with Gradle
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
@@ -96,12 +104,20 @@ jobs:
|
||||
task: "build"
|
||||
outputs: "build/allOutputs"
|
||||
- os: windows-2022
|
||||
artifact-name: Win32
|
||||
artifact-name: Win32FFI
|
||||
architecture: x86
|
||||
task: ":ntcoreffi:build"
|
||||
build-options: "-Pntcoreffibuild \"-Dorg.gradle.jvmargs=-Xmx1096m\""
|
||||
outputs: "ntcoreffi/build/outputs"
|
||||
- os: windows-2022
|
||||
artifact-name: Win64FFI
|
||||
architecture: x64
|
||||
task: ":ntcoreffi:build"
|
||||
build-options: "-Pntcoreffibuild -Pbuildwinarm64"
|
||||
outputs: "ntcoreffi/build/outputs"
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [validation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -119,16 +135,16 @@ jobs:
|
||||
keychain-password: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027'))))
|
||||
- name: Set Keychain Lock Timeout
|
||||
run: security set-keychain-settings -lut 21600
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027'))))
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
- name: Set Java Heap Size
|
||||
run: sed -i 's/-Xmx2g/-Xmx1g/g' gradle.properties
|
||||
if: matrix.artifact-name == 'Win32'
|
||||
@@ -159,7 +175,7 @@ jobs:
|
||||
run: ./gradlew copyAllOutputs --build-cache -PbuildServer -PskipJavaFormat -PdeveloperID=${{ secrets.APPLE_DEVELOPER_ID }} ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027'))))
|
||||
- name: Check disk free space (Windows)
|
||||
run: wmic logicaldisk get caption, freespace
|
||||
if: matrix.os == 'windows-2022'
|
||||
@@ -174,6 +190,7 @@ jobs:
|
||||
build-documentation:
|
||||
name: "Build - Documentation"
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -184,7 +201,7 @@ jobs:
|
||||
java-version: 17
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew docs:zipDocs --build-cache -PbuildServer ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
env:
|
||||
@@ -203,7 +220,7 @@ jobs:
|
||||
- name: Free Disk Space
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
tool-cache: false
|
||||
@@ -216,31 +233,31 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
with:
|
||||
repository: wpilibsuite/build-tools
|
||||
- uses: actions/download-artifact@v4
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
with:
|
||||
path: combiner/products/build/allOutputs
|
||||
- name: Flatten Artifacts
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
run: rsync -a --delete combiner/products/build/allOutputs/*/* combiner/products/build/allOutputs/
|
||||
- name: Check version number exists
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
run: |
|
||||
cat combiner/products/build/allOutputs/version.txt
|
||||
test -s combiner/products/build/allOutputs/version.txt
|
||||
- uses: actions/setup-java@v4
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
@@ -256,7 +273,7 @@ jobs:
|
||||
- name: Combine (Release)
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
startsWith(github.ref, 'refs/tags/v')
|
||||
startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
run: cd combiner && ./gradlew publish -Pallwpilib -PreleaseRepoPublish
|
||||
env:
|
||||
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
|
||||
@@ -265,7 +282,7 @@ jobs:
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
with:
|
||||
name: Maven
|
||||
path: ~/releases
|
||||
@@ -281,7 +298,7 @@ jobs:
|
||||
- uses: peter-evans/repository-dispatch@v3
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
startsWith(github.ref, 'refs/tags/v')
|
||||
startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
with:
|
||||
token: ${{ secrets.TOOL_REPO_ACCESS_TOKEN }}
|
||||
repository: wpilibsuite/${{ matrix.repo }}
|
||||
|
||||
14
.github/workflows/labeler.yml
vendored
Normal file
14
.github/workflows/labeler.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
sync-labels: true
|
||||
28
.github/workflows/lint-format.yml
vendored
28
.github/workflows/lint-format.yml
vendored
@@ -11,6 +11,13 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
|
||||
wpiformat:
|
||||
name: "wpiformat"
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -27,9 +34,11 @@ jobs:
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat==2024.45
|
||||
run: |
|
||||
python -m venv ${{ runner.temp }}/wpiformat
|
||||
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2024.51
|
||||
- name: Run
|
||||
run: wpiformat
|
||||
run: ${{ runner.temp }}/wpiformat/bin/wpiformat
|
||||
- name: Check output
|
||||
run: git --no-pager diff --exit-code HEAD
|
||||
- name: Generate diff
|
||||
@@ -51,7 +60,8 @@ jobs:
|
||||
tidy:
|
||||
name: "clang-tidy"
|
||||
runs-on: ubuntu-22.04
|
||||
container: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
needs: [validation]
|
||||
container: wpilib/ubuntu-base:22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -66,21 +76,24 @@ jobs:
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat==2024.45
|
||||
run: |
|
||||
python -m venv ${{ runner.temp }}/wpiformat
|
||||
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2024.51
|
||||
- name: Create compile_commands.json
|
||||
run: |
|
||||
./gradlew generateCompileCommands -Ptoolchain-optional-roboRio
|
||||
./.github/workflows/fix_compile_commands.py build/TargetedCompileCommands/linuxx86-64release/compile_commands.json
|
||||
./.github/workflows/fix_compile_commands.py build/TargetedCompileCommands/linuxx86-64debug/compile_commands.json
|
||||
- name: List changed files
|
||||
run: wpiformat -list-changed-files
|
||||
run: ${{ runner.temp }}/wpiformat/bin/wpiformat -list-changed-files
|
||||
- name: Run clang-tidy release
|
||||
run: wpiformat -no-format -tidy-changed -compile-commands=build/TargetedCompileCommands/linuxx86-64release -vv
|
||||
run: ${{ runner.temp }}/wpiformat/bin/wpiformat -no-format -tidy-changed -compile-commands=build/TargetedCompileCommands/linuxx86-64release -vv
|
||||
- name: Run clang-tidy debug
|
||||
run: wpiformat -no-format -tidy-changed -compile-commands=build/TargetedCompileCommands/linuxx86-64debug -vv
|
||||
run: ${{ runner.temp }}/wpiformat/bin/wpiformat -no-format -tidy-changed -compile-commands=build/TargetedCompileCommands/linuxx86-64debug -vv
|
||||
javaformat:
|
||||
name: "Java format"
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
container: wpilib/ubuntu-base:22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -114,6 +127,7 @@ jobs:
|
||||
documentation:
|
||||
name: "Documentation"
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
78
.github/workflows/pregen_all.py
vendored
78
.github/workflows/pregen_all.py
vendored
@@ -1,78 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main():
|
||||
script_path = Path(__file__).resolve()
|
||||
REPO_ROOT = script_path.parent.parent.parent
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--quickbuf_plugin",
|
||||
help="Path to the quickbuf protoc plugin",
|
||||
required=True,
|
||||
)
|
||||
args = parser.parse_args()
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/hal/generate_usage_reporting.py"], check=True
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/ntcore/generate_topics.py"], check=True
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/wpimath/generate_numbers.py"], check=True
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
f"{REPO_ROOT}/wpimath/generate_quickbuf.py",
|
||||
f"--quickbuf_plugin={args.quickbuf_plugin}",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
f"{REPO_ROOT}/wpimath/generate_nanopb.py",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/wpiunits/generate_units.py"], check=True
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/wpilibc/generate_hids.py"], check=True
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/wpilibj/generate_hids.py"], check=True
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/wpilibNewCommands/generate_hids.py"], check=True
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/wpilibc/generate_pwm_motor_controllers.py"],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/wpilibj/generate_pwm_motor_controllers.py"],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
f"{REPO_ROOT}/wpiutil/generate_nanopb.py",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
[sys.executable, f"{REPO_ROOT}/thirdparty/imgui_suite/generate_gl3w.py"],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(f"{REPO_ROOT}/thirdparty/imgui_suite/generate_fonts.sh", check=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
12
.github/workflows/pregenerate.yml
vendored
12
.github/workflows/pregenerate.yml
vendored
@@ -18,16 +18,8 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Install jinja and protobuf
|
||||
run: python -m pip install jinja2 protobuf grpcio-tools
|
||||
- name: Install protobuf dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler && wget https://github.com/HebiRobotics/QuickBuffers/releases/download/1.3.3/protoc-gen-quickbuf-1.3.3-linux-x86_64.exe && chmod +x protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
- name: Regenerate all
|
||||
run: python ./.github/workflows/pregen_all.py --quickbuf_plugin protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
- name: Run pregen
|
||||
uses: ./.github/actions/pregen
|
||||
- name: Add untracked files to index so they count as changes
|
||||
run: git add -A
|
||||
- name: Check output
|
||||
|
||||
8
.github/workflows/sanitizers.yml
vendored
8
.github/workflows/sanitizers.yml
vendored
@@ -29,11 +29,11 @@ jobs:
|
||||
ctest-env: ""
|
||||
ctest-flags: ""
|
||||
name: "${{ matrix.name }}"
|
||||
runs-on: ubuntu-22.04
|
||||
container: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
container: wpilib/roborio-cross-ubuntu:2025-24.04
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv4.5-java clang-14 libprotobuf-dev protobuf-compiler ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv-java clang-17 libprotobuf-dev protobuf-compiler ninja-build
|
||||
|
||||
- name: Install sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.5
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: configure
|
||||
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-14 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-14 -DWITH_JAVA=OFF ${{ matrix.cmake-flags }} ..
|
||||
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-17 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-17 -DWITH_JAVA=OFF ${{ matrix.cmake-flags }} ..
|
||||
env:
|
||||
SCCACHE_WEBDAV_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
SCCACHE_WEBDAV_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
|
||||
15
.github/workflows/sentinel-build.yml
vendored
15
.github/workflows/sentinel-build.yml
vendored
@@ -10,19 +10,26 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
|
||||
build-docker:
|
||||
if: (github.repository_owner == 'wpilibsuite' && github.ref == 'refs/heads/main') || github.event_name != 'schedule'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- container: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
- container: wpilib/roborio-cross-ubuntu:2025-22.04
|
||||
artifact-name: Athena
|
||||
build-options: "-Ponlylinuxathena"
|
||||
- container: wpilib/raspbian-cross-ubuntu:bullseye-22.04
|
||||
- container: wpilib/raspbian-cross-ubuntu:bookworm-22.04
|
||||
artifact-name: Arm32
|
||||
build-options: "-Ponlylinuxarm32"
|
||||
- container: wpilib/aarch64-cross-ubuntu:bullseye-22.04
|
||||
- container: wpilib/aarch64-cross-ubuntu:bookworm-22.04
|
||||
artifact-name: Arm64
|
||||
build-options: "-Ponlylinuxarm64"
|
||||
- container: wpilib/ubuntu-base:22.04
|
||||
@@ -30,6 +37,7 @@ jobs:
|
||||
build-options: "-Ponlylinuxx86-64"
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
- name: Free Disk Space
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
@@ -101,6 +109,7 @@ jobs:
|
||||
outputs: "ntcoreffi/build/outputs"
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [validation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
60
.github/workflows/tools.yml
vendored
60
.github/workflows/tools.yml
vendored
@@ -29,12 +29,13 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
- name: Build WPILib with Gradle
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
image: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
image: wpilib/roborio-cross-ubuntu:2025-22.04
|
||||
options: -v ${{ github.workspace }}:/work -w /work -e GITHUB_REF -e CI -e DISPLAY
|
||||
run: df . && rm -f semicolon_delimited_script && ./gradlew :wpilibc:publish :wpilibj:publish :wpilibNewCommands:publish :hal:publish :cameraserver:publish :ntcore:publish :cscore:publish :wpimath:publish :wpinet:publish :wpiutil:publish :apriltag:publish :wpiunits:publish :simulation:halsim_gui:publish :simulation:halsim_ds_socket:publish :fieldImages:publish :epilogue-processor:publish :epilogue-runtime:publish :thirdparty:googletest:publish -x test -x Javadoc -x doxygen --build-cache && cp -r /root/releases/maven/development /work
|
||||
run: df . && rm -f semicolon_delimited_script && ./gradlew :wpilibc:publish :wpilibj:publish :wpilibNewCommands:publish :hal:publish :cameraserver:publish :ntcore:publish :cscore:publish :wpimath:publish :wpinet:publish :wpiutil:publish :apriltag:publish :wpiunits:publish :simulation:halsim_gui:publish :simulation:halsim_ds_socket:publish :simulation:halsim_ws_server:publish :simulation:halsim_ws_client:publish :simulation:halsim_xrp:publish :fieldImages:publish :romiVendordep:publish :xrpVendordep:publish :epilogue-processor:publish :epilogue-runtime:publish :thirdparty:googletest:publish -x test -x Javadoc -x doxygen --build-cache && cp -r /root/releases/maven/development /work
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
@@ -148,3 +149,58 @@ jobs:
|
||||
path: |
|
||||
build/allOutputs/
|
||||
retention-days: 7
|
||||
|
||||
Robotpy:
|
||||
name: "Build - Robotpy"
|
||||
needs: [build-artifacts]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: robotpy/mostrobotpy
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
- name: Move artifacts
|
||||
run: mkdir -p ~/releases/maven/development && cp -r edu ~/releases/maven/development
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.13
|
||||
|
||||
#
|
||||
# Setup build caching
|
||||
#
|
||||
|
||||
- name: Set ccache size
|
||||
shell: bash
|
||||
id: ccache
|
||||
run: echo "MAX_SIZE=500M" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup ccache
|
||||
# uses: hendrikmuhs/ccache-action@v1.2.10
|
||||
uses: robotpy/ccache-action@fork
|
||||
with:
|
||||
key: ubuntu-22.04-3.13
|
||||
variant: ccache
|
||||
max-size: ${{ steps.ccache.outputs.max_size }}
|
||||
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip --disable-pip-version-check install -r rdev_requirements.txt
|
||||
|
||||
- name: Install numpy (needed for stubgen but broken in raspbian CI)
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip --disable-pip-version-check install numpy
|
||||
- name: Patch RobotPy rdev to use local development
|
||||
run: git config user.name github-actions && git config user.email github-actions@github.com && set -- ~/releases/maven/development/edu/wpi/first/wpiutil/wpiutil-cpp/*/ ; wpilibversion=$(basename $1) && echo $wpilibversion && sed --regexp-extended -i 's@(wpilib_bin_url =).*@\1 \"file:\/\/'"$HOME"'\/releases\/maven\/development"@' rdev.toml && sed --regexp-extended -i 's/(wpilib_bin_version =).*/\1 \"'"$wpilibversion"'\"/' rdev.toml && ./rdev.sh update-pyproject --commit
|
||||
- name: Build + test wheels
|
||||
shell: bash
|
||||
run: |
|
||||
./rdev.sh ci run
|
||||
env:
|
||||
RPYBUILD_STRIP_LIBPYTHON: "1"
|
||||
RPYBUILD_CC_LAUNCHER: ccache
|
||||
|
||||
6
.github/workflows/upstream-utils.yml
vendored
6
.github/workflows/upstream-utils.yml
vendored
@@ -120,12 +120,6 @@ jobs:
|
||||
./mpack.py clone
|
||||
./mpack.py copy-src
|
||||
./mpack.py format-patch
|
||||
- name: Run stack_walker.py
|
||||
run: |
|
||||
cd upstream_utils
|
||||
./stack_walker.py clone
|
||||
./stack_walker.py copy-src
|
||||
./stack_walker.py format-patch
|
||||
- name: Run memory.py
|
||||
run: |
|
||||
cd upstream_utils
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -255,3 +255,6 @@ bazel_auth.rc
|
||||
|
||||
# ctest
|
||||
/Testing/
|
||||
|
||||
# Meson
|
||||
.meson-subproject*
|
||||
|
||||
@@ -76,6 +76,7 @@ cmake_dependent_option(
|
||||
)
|
||||
option(WITH_CSCORE "Build cscore (needs OpenCV)" ON)
|
||||
option(WITH_NTCORE "Build ntcore" ON)
|
||||
option(WITH_WPICAL "Build wpical" OFF)
|
||||
option(WITH_WPIMATH "Build wpimath" ON)
|
||||
cmake_dependent_option(
|
||||
WITH_WPIUNITS
|
||||
@@ -142,6 +143,11 @@ if(WITH_DOCS)
|
||||
include(AddDoxygenDocs)
|
||||
add_doxygen_docs()
|
||||
endif()
|
||||
|
||||
if(WITH_WPICAL)
|
||||
find_package(Ceres CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(LIBSSH CONFIG 0.7.1)
|
||||
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
|
||||
@@ -314,6 +320,9 @@ if(WITH_GUI)
|
||||
add_subdirectory(glass)
|
||||
add_subdirectory(outlineviewer)
|
||||
add_subdirectory(sysid)
|
||||
if(WITH_WPICAL)
|
||||
add_subdirectory(wpical)
|
||||
endif()
|
||||
if(LIBSSH_FOUND)
|
||||
add_subdirectory(roborioteamnumbersetter)
|
||||
add_subdirectory(datalogtool)
|
||||
|
||||
@@ -1,69 +1,47 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
# Contributor Community Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
As members, contributors, and leaders, we commit to fostering a community where everyone feels safe, respected, and valued. We are dedicated to ensuring that participation in this community is harassment-free, inclusive, and welcoming, regardless of age, body type, abilities (visible or invisible), ethnicity, gender identity or expression, sexual orientation, socioeconomic background, education, nationality, personal appearance, race, or religion.
|
||||
|
||||
Above all, we pledge to act with integrity, kindness, and empathy—striving to be not only good participants but also good humans.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
Positive and respectful behavior is essential to creating a thriving community. This includes:
|
||||
|
||||
* Exhibiting Gracious Professionalism® at all times. Gracious Professionalism
|
||||
* Practicing **Gracious Professionalism®** at all times. Gracious Professionalism
|
||||
is a way of doing things that encourages high-quality work, emphasizes the
|
||||
value of others, and respects individuals and the community.
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
* Showing empathy, kindness, and patience.
|
||||
* Respecting diverse perspectives and experiences.
|
||||
* Giving and receiving constructive feedback with openness and humility.
|
||||
* Owning mistakes, apologizing when necessary, and learning from them.
|
||||
* Prioritizing the well-being and success of the entire community over individual interests.
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
Unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Using sexualized language, imagery, or making inappropriate advances
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
* Harassment in any form, whether public or private.
|
||||
* Sharing private information (e.g., email or physical addresses) without explicit consent.
|
||||
|
||||
* Any behavior that is unprofessional, harmful, or exclusionary.
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
Community leaders are responsible for maintaining these standards and will take appropriate action to address any behavior deemed harmful, threatening, or inappropriate. Actions may include removing content, issuing warnings, or, when necessary, banning individuals. Moderation decisions will be communicated transparently where appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
This Code of Conduct applies to all community spaces, events, and instances where individuals represent the community (e.g., official email accounts, social media posts, or in-person/virtual events).
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[conduct@wpilib.org](mailto:conduct@wpilib.org).
|
||||
[wpilib@wpi.edu](mailto:wpilib@wpi.edu).
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
@@ -115,6 +93,9 @@ individual, or aggression toward or disparagement of classes of individuals.
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## A Note on Kindness
|
||||
Building a community isn’t just about rules—it’s about connection. Every interaction is an opportunity to be understanding, compassionate, and supportive. Being a good human is the key to our ethos.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
|
||||
@@ -80,7 +80,7 @@ xₖ₊₁ = Axₖ + Buₖ
|
||||
|
||||
Changes should be submitted as a Pull Request against the main branch of WPILib. For most changes, commits will be squashed upon merge. For particularly large changes, multiple commits are ok, but assume one commit unless asked otherwise. We may ask you to break a PR into multiple standalone PRs or commits for rebase within one PR to separate unrelated changes. No change will be merged unless it is up to date with the current main branch. We do this to make sure that the git history isn't too cluttered.
|
||||
|
||||
During the build season, breaking changes or other changes intended for the next season can be created as a pull request against the development branch of WPILib. After the season is over, the changes in the development branch will be merged into main.
|
||||
Particularly large and/or breaking changes should be targeted to the 2027 branch, which targets the [SystemCore Robot Controller](https://community.firstinspires.org/introducing-the-future-mobile-robot-controller). The intent is minimize changes for 2026, to allow development to focus on preparing for 2027.
|
||||
|
||||
### Merge Process
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2024 FIRST and other WPILib contributors
|
||||
Copyright (c) 2009-2025 FIRST and other WPILib contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -59,6 +59,8 @@ Using Gradle makes building WPILib very straightforward. It only has a few depen
|
||||
|
||||
On macOS ARM, run `softwareupdate --install-rosetta`. This is necessary to be able to use the macOS x86 roboRIO toolchain on ARM.
|
||||
|
||||
On linux, run `sudo apt install gfortran`. This is necessary to be able to build WPIcal on linux platforms.
|
||||
|
||||
## Setup
|
||||
|
||||
Clone the WPILib repository and follow the instructions above for installing any required tooling. The build process uses versioning information from git. Downloading the source is not sufficient to run the build.
|
||||
@@ -134,6 +136,9 @@ If you have installed the FRC Toolchain to a directory other than the default, o
|
||||
|
||||
Once a PR has been submitted, formatting can be run in CI by commenting `/format` on the PR. A new commit will be pushed with the formatting changes.
|
||||
|
||||
> [!NOTE]
|
||||
> The `/format` action has been temporarily disabled. The individual formatting commands can be run locally as shown below. Alternately, the Lint and Format action for a PR will upload a patch file that can be downloaded and applied manually.
|
||||
|
||||
#### wpiformat
|
||||
|
||||
wpiformat can be executed anywhere in the repository via `py -3 -m wpiformat` on Windows or `python3 -m wpiformat` on other platforms.
|
||||
|
||||
@@ -15,7 +15,8 @@ licenses, and/or restrictions:
|
||||
|
||||
Program Locations
|
||||
------- ---------
|
||||
Google Test gtest
|
||||
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
|
||||
@@ -32,17 +33,29 @@ jQuery wpinet/src/main/native/resources/jquery-*
|
||||
popper.js wpinet/src/main/native/resources/popper-*
|
||||
units wpimath/src/main/native/include/units/
|
||||
Eigen wpimath/src/main/native/thirdparty/eigen/include/
|
||||
StackWalker wpiutil/src/main/native/windows/StackWalker.*
|
||||
GHC filesystem wpiutil/src/main/native/thirdparty/include/wpi/ghc/
|
||||
Team 254 Library wpilibj/src/main/java/edu/wpi/first/wpilibj/spline/SplineParameterizer.java
|
||||
wpilibj/src/main/java/edu/wpi/first/wpilibj/trajectory/TrajectoryParameterizer.java
|
||||
wpilibc/src/main/native/include/spline/SplineParameterizer.h
|
||||
wpilibc/src/main/native/include/trajectory/TrajectoryParameterizer.h
|
||||
wpilibc/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp
|
||||
Team 254 Library wpimath/src/main/java/edu/wpi/first/math/spline/SplineParameterizer.java
|
||||
wpimath/src/main/java/edu/wpi/first/math/trajectory/TrajectoryParameterizer.java
|
||||
wpimath/src/main/native/include/frc/spline/SplineParameterizer.h
|
||||
wpimath/src/main/native/include/frc/trajectory/TrajectoryParameterizer.h
|
||||
wpimath/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp
|
||||
Portable File Dialogs wpigui/src/main/native/include/portable-file-dialogs.h
|
||||
V8 export-template wpiutil/src/main/native/include/wpi/SymbolExports.h
|
||||
GCEM wpimath/src/main/native/thirdparty/gcem/include/
|
||||
Sleipnir wpimath/src/main/native/thirdparty/sleipnir
|
||||
Debugging wpiutil/src/main/native/thirdparty/debugging
|
||||
argparse wpiutil/src/main/native/thirdparty/argparse/include/wpi/argparse.h
|
||||
apriltag apriltag/src/main/native/thirdparty/apriltag
|
||||
glfw thirdparty/imgui_suite/glfw
|
||||
Dear ImGui thirdparty/imgui_suite/imgui
|
||||
implot thirdparty/imgui_suite/implot
|
||||
memory wpiutil/src/main/native/thirdparty/memory
|
||||
nanopb wpiutil/src/main/native/thirdparty/nanopb
|
||||
protobuf wpiutil/src/main/native/thirdparty/protobuf
|
||||
mrcal wpical/src/main/native/thirdparty/mrcal
|
||||
libdogleg wpical/src/main/native/thirdparty/libdogleg
|
||||
Simd hal/src/main/native/athena/simd
|
||||
|
||||
Additionally, glfw, memory, and nanopb were all modified for use in WPILib.
|
||||
|
||||
==============================================================================
|
||||
Google Test License
|
||||
@@ -461,7 +474,7 @@ limitations under the License.
|
||||
|
||||
|
||||
==============================================================================
|
||||
MPacks License
|
||||
MPack License
|
||||
==============================================================================
|
||||
The MIT License (MIT)
|
||||
|
||||
@@ -1012,35 +1025,6 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
|
||||
===================
|
||||
StackWalker License
|
||||
===================
|
||||
Copyright (c) 2005-2013, Jochen Kalmbach
|
||||
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 Jochen Kalmbach 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.
|
||||
|
||||
|
||||
================
|
||||
Team 254 Library
|
||||
================
|
||||
@@ -1077,33 +1061,6 @@ and/or modify it under the terms of the Do What the **** You Want
|
||||
to Public License, Version 2, as published by the WTFPL Task Force.
|
||||
See http://www.wtfpl.net/ for more details.
|
||||
|
||||
======================
|
||||
Boost Software License
|
||||
======================
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
======
|
||||
fmtlib
|
||||
======
|
||||
@@ -1135,29 +1092,6 @@ of this Software are embedded into a machine-executable object form of such
|
||||
source code, you may redistribute such embedded portions in such object form
|
||||
without including the above copyright and permission notices.
|
||||
|
||||
==============
|
||||
GHC filesystem
|
||||
==============
|
||||
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
|
||||
|
||||
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.
|
||||
|
||||
==================
|
||||
V8 export-template
|
||||
==================
|
||||
@@ -1224,3 +1158,544 @@ Redistribution and use in source and binary forms, with or without modification,
|
||||
3. Neither the name of the copyright holder 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 HOLDER 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.
|
||||
|
||||
=================
|
||||
Debugging License
|
||||
=================
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 René Ferdinand Rivera Morell
|
||||
Copyright (c) 2018 Isabella Muerte
|
||||
|
||||
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.
|
||||
|
||||
================
|
||||
argparse License
|
||||
================
|
||||
Copyright (c) 2018 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>
|
||||
|
||||
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.
|
||||
|
||||
================
|
||||
apriltag License
|
||||
================
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (C) 2013-2016, The Regents of The University of Michigan.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
||||
|
||||
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 HOLDER 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.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the Regents of The University of Michigan.
|
||||
|
||||
============
|
||||
gl3w License
|
||||
============
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
============
|
||||
glfw License
|
||||
============
|
||||
Copyright (c) 2002-2006 Marcus Geelnard
|
||||
|
||||
Copyright (c) 2006-2019 Camilla Löwy
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would
|
||||
be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not
|
||||
be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
==================
|
||||
Dear ImGui License
|
||||
==================
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2024 Omar Cornut
|
||||
|
||||
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.
|
||||
|
||||
==============
|
||||
implot License
|
||||
==============
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Evan Pezent
|
||||
|
||||
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.
|
||||
|
||||
==============
|
||||
memory License
|
||||
==============
|
||||
Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
|
||||
|
||||
This software is provided 'as-is', without any express or
|
||||
implied warranty. In no event will the authors be held
|
||||
liable for any damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute
|
||||
it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented;
|
||||
you must not claim that you wrote the original software.
|
||||
If you use this software in a product, an acknowledgment
|
||||
in the product documentation would be appreciated but
|
||||
is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such,
|
||||
and must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any
|
||||
source distribution.
|
||||
|
||||
==============
|
||||
nanopb License
|
||||
==============
|
||||
Copyright (c) 2011 Petteri Aimonen <jpa at nanopb.mail.kapsi.fi>
|
||||
|
||||
This software is provided 'as-is', without any express or
|
||||
implied warranty. In no event will the authors be held liable
|
||||
for any damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
================
|
||||
protobuf License
|
||||
================
|
||||
Copyright 2008 Google Inc. 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.
|
||||
|
||||
Code generated by the Protocol Buffer compiler is owned by the owner
|
||||
of the input file used when generating it. This code is not
|
||||
standalone and requires a support library to be linked with it. This
|
||||
support library is itself covered by the above license.
|
||||
|
||||
===========
|
||||
stb License
|
||||
===========
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
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 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.
|
||||
|
||||
=============
|
||||
mrcal License
|
||||
=============
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) 2017-2023 California Institute of Technology ("Caltech"). U.S.
|
||||
Government sponsorship acknowledged. All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
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.
|
||||
|
||||
=================
|
||||
libdogleg License
|
||||
=================
|
||||
Copyright 2011 Oblong Industries 2017 Dima Kogan <dima@secretsauce.net>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
|
||||
The full text of the license is available at http://www.gnu.org/licenses
|
||||
|
||||
============
|
||||
Simd License
|
||||
============
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2011-2017 Ihar Yermalayeu
|
||||
|
||||
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.
|
||||
|
||||
47
WORKSPACE
47
WORKSPACE
@@ -35,8 +35,8 @@ maven_install(
|
||||
# Download toolchains
|
||||
http_archive(
|
||||
name = "rules_bzlmodrio_toolchains",
|
||||
sha256 = "2ef1cafce7f4fd4e909bb5de8b0dc771a934646afd55d5f100ff31f6b500df98",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodRio_toolchains/releases/download/2024-1.bcr1/rules_bzlmodRio_toolchains-2024-1.bcr1.tar.gz",
|
||||
sha256 = "ff25b5f9445cbd43759be4c6582b987d1065cf817c593eedc7ada1a699298c84",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodRio_toolchains/releases/download/2025-1.bcr2/rules_bzlmodRio_toolchains-2025-1.bcr2.tar.gz",
|
||||
)
|
||||
|
||||
load("@rules_bzlmodrio_toolchains//:maven_deps.bzl", "setup_legacy_setup_toolchains_dependencies")
|
||||
@@ -50,8 +50,8 @@ load_toolchains()
|
||||
#
|
||||
http_archive(
|
||||
name = "rules_bzlmodrio_jdk",
|
||||
sha256 = "a00d5fa971fbcad8a17b1968cdc5350688397035e90b0cb94e040d375ecd97b4",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodRio_jdk/releases/download/17.0.8.1-1/rules_bzlmodRio_jdk-17.0.8.1-1.tar.gz",
|
||||
sha256 = "81869fe9860e39b17e4a9bc1d33c1ca2faede7e31d9538ed0712406f753a2163",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodRio_jdk/releases/download/17.0.12-7/rules_bzlmodRio_jdk-17.0.12-7.tar.gz",
|
||||
)
|
||||
|
||||
load("@rules_bzlmodrio_jdk//:maven_deps.bzl", "setup_legacy_setup_jdk_dependencies")
|
||||
@@ -62,23 +62,35 @@ register_toolchains(
|
||||
"@local_roborio//:macos",
|
||||
"@local_roborio//:linux",
|
||||
"@local_roborio//:windows",
|
||||
"@local_raspi_32//:macos",
|
||||
"@local_raspi_32//:linux",
|
||||
"@local_raspi_32//:windows",
|
||||
"@local_systemcore//:macos",
|
||||
"@local_systemcore//:linux",
|
||||
"@local_systemcore//:windows",
|
||||
"@local_raspi_bullseye_32//:macos",
|
||||
"@local_raspi_bullseye_32//:linux",
|
||||
"@local_raspi_bullseye_32//:windows",
|
||||
"@local_raspi_bookworm_32//:macos",
|
||||
"@local_raspi_bookworm_32//:linux",
|
||||
"@local_raspi_bookworm_32//:windows",
|
||||
"@local_bullseye_32//:macos",
|
||||
"@local_bullseye_32//:linux",
|
||||
"@local_bullseye_32//:windows",
|
||||
"@local_bullseye_64//:macos",
|
||||
"@local_bullseye_64//:linux",
|
||||
"@local_bullseye_64//:windows",
|
||||
"@local_bookworm_32//:macos",
|
||||
"@local_bookworm_32//:linux",
|
||||
"@local_bookworm_32//:windows",
|
||||
"@local_bookworm_64//:macos",
|
||||
"@local_bookworm_64//:linux",
|
||||
"@local_bookworm_64//:windows",
|
||||
)
|
||||
|
||||
setup_legacy_setup_jdk_dependencies()
|
||||
|
||||
http_archive(
|
||||
name = "bzlmodrio-ni",
|
||||
sha256 = "197fceac88bf44fb8427d5e000b0083118d3346172dd2ad31eccf83a5e61b3ce",
|
||||
url = "https://github.com/wpilibsuite/bzlmodRio-ni/releases/download/2025.0.0/bzlmodRio-ni-2025.0.0.tar.gz",
|
||||
sha256 = "fff62c3cb3e83f9a0d0a01f1739477c9ca5e9a6fac05be1ad59dafcd385801f7",
|
||||
url = "https://github.com/wpilibsuite/bzlmodRio-ni/releases/download/2025.2.0/bzlmodRio-ni-2025.2.0.tar.gz",
|
||||
)
|
||||
|
||||
load("@bzlmodrio-ni//:maven_cpp_deps.bzl", "setup_legacy_bzlmodrio_ni_cpp_dependencies")
|
||||
@@ -87,8 +99,8 @@ setup_legacy_bzlmodrio_ni_cpp_dependencies()
|
||||
|
||||
http_archive(
|
||||
name = "bzlmodrio-opencv",
|
||||
sha256 = "5314cce05b49451a46bf3e3140fc401342e53d5f3357612ed4473e59bb616cba",
|
||||
url = "https://github.com/wpilibsuite/bzlmodRio-opencv/releases/download/2024.4.8.0-4.bcr1/bzlmodRio-opencv-2024.4.8.0-4.bcr1.tar.gz",
|
||||
sha256 = "ba3f4910ce9cc0e08abff732aeb5835b1bcfd864ca5296edeadcf2935f7e81b9",
|
||||
url = "https://github.com/wpilibsuite/bzlmodRio-opencv/releases/download/2025.4.10.0-3.bcr1/bzlmodRio-opencv-2025.4.10.0-3.bcr1.tar.gz",
|
||||
)
|
||||
|
||||
load("@bzlmodrio-opencv//:maven_cpp_deps.bzl", "setup_legacy_bzlmodrio_opencv_cpp_dependencies")
|
||||
@@ -98,3 +110,16 @@ setup_legacy_bzlmodrio_opencv_cpp_dependencies()
|
||||
load("@bzlmodrio-opencv//:maven_java_deps.bzl", "setup_legacy_bzlmodrio_opencv_java_dependencies")
|
||||
|
||||
setup_legacy_bzlmodrio_opencv_java_dependencies()
|
||||
|
||||
http_archive(
|
||||
name = "build_bazel_apple_support",
|
||||
sha256 = "c4bb2b7367c484382300aee75be598b92f847896fb31bbd22f3a2346adf66a80",
|
||||
url = "https://github.com/bazelbuild/apple_support/releases/download/1.15.1/apple_support.1.15.1.tar.gz",
|
||||
)
|
||||
|
||||
load(
|
||||
"@build_bazel_apple_support//lib:repositories.bzl",
|
||||
"apple_support_dependencies",
|
||||
)
|
||||
|
||||
apple_support_dependencies()
|
||||
|
||||
112
apriltag/BUILD.bazel
Normal file
112
apriltag/BUILD.bazel
Normal file
@@ -0,0 +1,112 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load("@rules_java//java:defs.bzl", "java_binary", "java_library")
|
||||
load("@rules_python//python:defs.bzl", "py_binary")
|
||||
load("//shared/bazel/rules/gen:gen-resources.bzl", "generate_resources")
|
||||
|
||||
cc_library(
|
||||
name = "thirdparty-apriltag",
|
||||
srcs = glob(["src/main/native/thirdparty/apriltag/src/**"]),
|
||||
hdrs = glob(["src/main/native/thirdparty/apriltag/include/**"]),
|
||||
copts = select({
|
||||
"@bazel_tools//src/conditions:darwin": [
|
||||
"-Wno-format-nonliteral",
|
||||
"-Wno-gnu-zero-variadic-macro-arguments",
|
||||
"-Wno-uninitialized",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-type-limits",
|
||||
],
|
||||
"@bazel_tools//src/conditions:windows": [
|
||||
"/wd4005",
|
||||
"/wd4018",
|
||||
"/wd4244",
|
||||
"/wd4267",
|
||||
"/wd4996",
|
||||
],
|
||||
"@rules_bzlmodrio_toolchains//constraints/combined:is_linux": [
|
||||
"-Wno-format-nonliteral",
|
||||
"-Wno-maybe-uninitialized",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-type-limits",
|
||||
],
|
||||
}),
|
||||
includes = ["src/main/native/thirdparty/apriltag/include/common"],
|
||||
strip_include_prefix = "src/main/native/thirdparty/apriltag/include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
generate_resources(
|
||||
name = "generate-resources",
|
||||
namespace = "frc",
|
||||
prefix = "APRILTAG",
|
||||
resource_files = glob(["src/main/native/resources/**"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "apriltag.static",
|
||||
srcs = [":generate-resources"] + glob(
|
||||
["src/main/native/cpp/**"],
|
||||
exclude = ["src/main/native/cpp/jni/**"],
|
||||
),
|
||||
hdrs = glob(["src/main/native/include/**/*"]),
|
||||
defines = ["WPILIB_EXPORTS"],
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":thirdparty-apriltag",
|
||||
"//wpimath:wpimath.static",
|
||||
"//wpiutil:wpiutil.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "apriltag-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
resource_strip_prefix = "apriltag/src/main/native/resources",
|
||||
resources = glob(["src/main/native/resources/**"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//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",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "apriltag-cpp-test",
|
||||
size = "small",
|
||||
srcs = glob(["src/test/native/cpp/**"]),
|
||||
tags = [
|
||||
"no-asan",
|
||||
],
|
||||
deps = [
|
||||
":apriltag.static",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
":apriltag.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "DevMain-Java",
|
||||
srcs = ["src/dev/java/edu/wpi/first/apriltag/DevMain.java"],
|
||||
main_class = "edu.wpi.first.apriltag.DevMain",
|
||||
deps = [
|
||||
":apriltag-java",
|
||||
],
|
||||
)
|
||||
|
||||
py_binary(
|
||||
name = "convert_apriltag_layouts",
|
||||
srcs = ["convert_apriltag_layouts.py"],
|
||||
tags = ["manual"],
|
||||
)
|
||||
@@ -7,10 +7,11 @@ AprilTagFields expects.
|
||||
|
||||
The input CSV has the following format:
|
||||
|
||||
* Columns: ID, X, Y, Z, Rotation
|
||||
* Columns: ID, X, Y, Z, Z Rotation, Y Rotation
|
||||
* ID is a positive integer
|
||||
* X, Y, and Z are decimal inches
|
||||
* Rotation is yaw in degrees
|
||||
* Z Rotation is yaw in degrees
|
||||
* Y Rotation is pitch in degrees
|
||||
|
||||
The values come from a table in the layout marking diagram (e.g.,
|
||||
https://firstfrc.blob.core.windows.net/frc2024/FieldAssets/2024LayoutMarkingDiagram.pdf).
|
||||
@@ -48,13 +49,14 @@ def main():
|
||||
x = float(row[1])
|
||||
y = float(row[2])
|
||||
z = float(row[3])
|
||||
rotation = float(row[4])
|
||||
zRotation = float(row[4])
|
||||
yRotation = float(row[5])
|
||||
|
||||
# Turn yaw into quaternion
|
||||
q = geometry.Rotation3d(
|
||||
units.radians(0.0),
|
||||
units.radians(0.0),
|
||||
units.degreesToRadians(rotation),
|
||||
units.radians(0),
|
||||
units.degreesToRadians(yRotation),
|
||||
units.degreesToRadians(zRotation),
|
||||
).getQuaternion()
|
||||
|
||||
json_data["tags"].append(
|
||||
|
||||
@@ -13,13 +13,17 @@ public enum AprilTagFields {
|
||||
/** 2023 Charged Up. */
|
||||
k2023ChargedUp("2023-chargedup.json"),
|
||||
/** 2024 Crescendo. */
|
||||
k2024Crescendo("2024-crescendo.json");
|
||||
k2024Crescendo("2024-crescendo.json"),
|
||||
/** 2025 Reefscape Welded (see TU 12). */
|
||||
k2025ReefscapeWelded("2025-reefscape-welded.json"),
|
||||
/** 2025 Reefscape AndyMark (see TU 12). */
|
||||
k2025ReefscapeAndyMark("2025-reefscape-andymark.json");
|
||||
|
||||
/** Base resource directory. */
|
||||
public static final String kBaseResourceDir = "/edu/wpi/first/apriltag/";
|
||||
|
||||
/** Alias to the current game. */
|
||||
public static final AprilTagFields kDefaultField = k2024Crescendo;
|
||||
public static final AprilTagFields kDefaultField = k2025ReefscapeWelded;
|
||||
|
||||
/** Resource filename. */
|
||||
public final String m_resourceFile;
|
||||
|
||||
@@ -133,6 +133,8 @@ namespace frc {
|
||||
std::string_view GetResource_2022_rapidreact_json();
|
||||
std::string_view GetResource_2023_chargedup_json();
|
||||
std::string_view GetResource_2024_crescendo_json();
|
||||
std::string_view GetResource_2025_reefscape_welded_json();
|
||||
std::string_view GetResource_2025_reefscape_andymark_json();
|
||||
|
||||
} // namespace frc
|
||||
|
||||
@@ -148,6 +150,12 @@ AprilTagFieldLayout AprilTagFieldLayout::LoadField(AprilTagField field) {
|
||||
case AprilTagField::k2024Crescendo:
|
||||
fieldString = GetResource_2024_crescendo_json();
|
||||
break;
|
||||
case AprilTagField::k2025ReefscapeWelded:
|
||||
fieldString = GetResource_2025_reefscape_welded_json();
|
||||
break;
|
||||
case AprilTagField::k2025ReefscapeAndyMark:
|
||||
fieldString = GetResource_2025_reefscape_andymark_json();
|
||||
break;
|
||||
case AprilTagField::kNumFields:
|
||||
throw std::invalid_argument("Invalid Field");
|
||||
}
|
||||
|
||||
@@ -20,6 +20,12 @@ enum class AprilTagField {
|
||||
k2023ChargedUp,
|
||||
/// 2024 Crescendo.
|
||||
k2024Crescendo,
|
||||
/// 2025 Reefscape AndyMark (see TU12).
|
||||
k2025ReefscapeAndyMark,
|
||||
/// 2025 Reefscape Welded (see TU12).
|
||||
k2025ReefscapeWelded,
|
||||
/// Alias to the current game.
|
||||
kDefaultField = k2025ReefscapeWelded,
|
||||
|
||||
// This is a placeholder for denoting the last supported field. This should
|
||||
// always be the last entry in the enum and should not be used by users
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
ID,X,Y,Z,Rotation
|
||||
1,593.68,9.68,53.38,120
|
||||
2,637.21,34.79,53.38,120
|
||||
3,652.73,196.17,57.13,180
|
||||
4,652.73,218.42,57.13,180
|
||||
5,578.77,323.00,53.38,270
|
||||
6,72.5,323.00,53.38,270
|
||||
7,-1.50,218.42,57.13,0
|
||||
8,-1.50,196.17,57.13,0
|
||||
9,14.02,34.79,53.38,60
|
||||
10,57.54,9.68,53.38,60
|
||||
11,468.69,146.19,52.00,300
|
||||
12,468.69,177.10,52.00,60
|
||||
13,441.74,161.62,52.00,180
|
||||
14,209.48,161.62,52.00,0
|
||||
15,182.73,177.10,52.00,120
|
||||
16,182.73,146.19,52.00,240
|
||||
|
@@ -0,0 +1,23 @@
|
||||
ID,X,Y,Z,Z-Rotation,X-Rotation
|
||||
1,656.98,24.73,58.5,126,0
|
||||
2,656.98,291.9,58.5,234,0
|
||||
3,452.4,316.21,51.25,270,0
|
||||
4,365.2,241.44,73.54,0,30
|
||||
5,365.2,75.19,73.54,0,30
|
||||
6,530.49,129.97,12.13,300,0
|
||||
7,546.87,158.3,12.13,0,0
|
||||
8,530.49,186.63,12.13,60,0
|
||||
9,497.77,186.63,12.13,120,0
|
||||
10,481.39,158.3,12.13,180,0
|
||||
11,497.77,129.97,12.13,240,0
|
||||
12,33.91,24.73,58.5,54,0
|
||||
13,33.91,291.9,58.5,306,0
|
||||
14,325.68,241.44,73.54,180,30
|
||||
15,325.68,75.19,73.54,180,30
|
||||
16,238.49,0.42,51.25,90,0
|
||||
17,160.39,129.97,12.13,240,0
|
||||
18,144,158.3,12.13,180,0
|
||||
19,160.39,186.63,12.13,120,0
|
||||
20,193.1,186.63,12.13,60,0
|
||||
21,209.49,158.3,12.13,0,0
|
||||
22,193.1,129.97,12.13,300,0
|
||||
|
@@ -0,0 +1,404 @@
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"ID": 1,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.687292,
|
||||
"y": 0.628142,
|
||||
"z": 1.4859
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.4539904997395468,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8910065241883678
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 2,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.687292,
|
||||
"y": 7.414259999999999,
|
||||
"z": 1.4859
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.45399049973954675,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8910065241883679
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 3,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.49096,
|
||||
"y": 8.031733999999998,
|
||||
"z": 1.30175
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 9.276079999999999,
|
||||
"y": 6.132575999999999,
|
||||
"z": 1.8679160000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.9659258262890683,
|
||||
"X": 0.0,
|
||||
"Y": 0.25881904510252074,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 5,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 9.276079999999999,
|
||||
"y": 1.9098259999999998,
|
||||
"z": 1.8679160000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.9659258262890683,
|
||||
"X": 0.0,
|
||||
"Y": 0.25881904510252074,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 6,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 13.474446,
|
||||
"y": 3.3012379999999997,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.8660254037844387,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 7,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 13.890498,
|
||||
"y": 4.0208200000000005,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 13.474446,
|
||||
"y": 4.740402,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8660254037844387,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 9,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.643358,
|
||||
"y": 4.740402,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.5000000000000001,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844386
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 10,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.227305999999999,
|
||||
"y": 4.0208200000000005,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 11,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.643358,
|
||||
"y": 3.3012379999999997,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.4999999999999998,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844387
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.8613139999999999,
|
||||
"y": 0.628142,
|
||||
"z": 1.4859
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8910065241883679,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.45399049973954675
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 13,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.8613139999999999,
|
||||
"y": 7.414259999999999,
|
||||
"z": 1.4859
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.8910065241883678,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.45399049973954686
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 14,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 8.272272,
|
||||
"y": 6.132575999999999,
|
||||
"z": 1.8679160000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 5.914589856893349e-17,
|
||||
"X": -0.25881904510252074,
|
||||
"Y": 1.5848095757158825e-17,
|
||||
"Z": 0.9659258262890683
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 15,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 8.272272,
|
||||
"y": 1.9098259999999998,
|
||||
"z": 1.8679160000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 5.914589856893349e-17,
|
||||
"X": -0.25881904510252074,
|
||||
"Y": 1.5848095757158825e-17,
|
||||
"Z": 0.9659258262890683
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 16,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 6.057646,
|
||||
"y": 0.010667999999999999,
|
||||
"z": 1.30175
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 17,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.073905999999999,
|
||||
"y": 3.3012379999999997,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.4999999999999998,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844387
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 18,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 3.6576,
|
||||
"y": 4.0208200000000005,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 19,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.073905999999999,
|
||||
"y": 4.740402,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.5000000000000001,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844386
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 20,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.904739999999999,
|
||||
"y": 4.740402,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8660254037844387,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 21,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 5.321046,
|
||||
"y": 4.0208200000000005,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 22,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.904739999999999,
|
||||
"y": 3.3012379999999997,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.8660254037844387,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"field": {
|
||||
"length": 17.548,
|
||||
"width": 8.042
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
ID,X,Y,Z,Z-Rotation,X-Rotation
|
||||
1,657.37,25.8,58.5,126,0
|
||||
2,657.37,291.2,58.5,234,0
|
||||
3,455.15,317.15,51.25,270,0
|
||||
4,365.2,241.64,73.54,0,30
|
||||
5,365.2,75.39,73.54,0,30
|
||||
6,530.49,130.17,12.13,300,0
|
||||
7,546.87,158.5,12.13,0,0
|
||||
8,530.49,186.83,12.13,60,0
|
||||
9,497.77,186.83,12.13,120,0
|
||||
10,481.39,158.5,12.13,180,0
|
||||
11,497.77,130.17,12.13,240,0
|
||||
12,33.51,25.8,58.5,54,0
|
||||
13,33.51,291.2,58.5,306,0
|
||||
14,325.68,241.64,73.54,180,30
|
||||
15,325.68,75.39,73.54,180,30
|
||||
16,235.73,-0.15,51.25,90,0
|
||||
17,160.39,130.17,12.13,240,0
|
||||
18,144,158.5,12.13,180,0
|
||||
19,160.39,186.83,12.13,120,0
|
||||
20,193.1,186.83,12.13,60,0
|
||||
21,209.49,158.5,12.13,0,0
|
||||
22,193.1,130.17,12.13,300,0
|
||||
|
@@ -0,0 +1,404 @@
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"ID": 1,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.697198,
|
||||
"y": 0.65532,
|
||||
"z": 1.4859
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.4539904997395468,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8910065241883678
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 2,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.697198,
|
||||
"y": 7.3964799999999995,
|
||||
"z": 1.4859
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.45399049973954675,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8910065241883679
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 3,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.560809999999998,
|
||||
"y": 8.05561,
|
||||
"z": 1.30175
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 9.276079999999999,
|
||||
"y": 6.137656,
|
||||
"z": 1.8679160000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.9659258262890683,
|
||||
"X": 0.0,
|
||||
"Y": 0.25881904510252074,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 5,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 9.276079999999999,
|
||||
"y": 1.914906,
|
||||
"z": 1.8679160000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.9659258262890683,
|
||||
"X": 0.0,
|
||||
"Y": 0.25881904510252074,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 6,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 13.474446,
|
||||
"y": 3.3063179999999996,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.8660254037844387,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 7,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 13.890498,
|
||||
"y": 4.0259,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 13.474446,
|
||||
"y": 4.745482,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8660254037844387,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 9,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.643358,
|
||||
"y": 4.745482,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.5000000000000001,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844386
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 10,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.227305999999999,
|
||||
"y": 4.0259,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 11,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.643358,
|
||||
"y": 3.3063179999999996,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.4999999999999998,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844387
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.851154,
|
||||
"y": 0.65532,
|
||||
"z": 1.4859
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8910065241883679,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.45399049973954675
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 13,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.851154,
|
||||
"y": 7.3964799999999995,
|
||||
"z": 1.4859
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.8910065241883678,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.45399049973954686
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 14,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 8.272272,
|
||||
"y": 6.137656,
|
||||
"z": 1.8679160000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 5.914589856893349e-17,
|
||||
"X": -0.25881904510252074,
|
||||
"Y": 1.5848095757158825e-17,
|
||||
"Z": 0.9659258262890683
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 15,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 8.272272,
|
||||
"y": 1.914906,
|
||||
"z": 1.8679160000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 5.914589856893349e-17,
|
||||
"X": -0.25881904510252074,
|
||||
"Y": 1.5848095757158825e-17,
|
||||
"Z": 0.9659258262890683
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 16,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 5.9875419999999995,
|
||||
"y": -0.0038099999999999996,
|
||||
"z": 1.30175
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 17,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.073905999999999,
|
||||
"y": 3.3063179999999996,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.4999999999999998,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844387
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 18,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 3.6576,
|
||||
"y": 4.0259,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 19,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.073905999999999,
|
||||
"y": 4.745482,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.5000000000000001,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844386
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 20,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.904739999999999,
|
||||
"y": 4.745482,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8660254037844387,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 21,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 5.321046,
|
||||
"y": 4.0259,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 22,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.904739999999999,
|
||||
"y": 3.3063179999999996,
|
||||
"z": 0.308102
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.8660254037844387,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"field": {
|
||||
"length": 17.548,
|
||||
"width": 8.052
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ plugins {
|
||||
id 'idea'
|
||||
id 'visual-studio'
|
||||
id 'net.ltgt.errorprone' version '3.1.0' apply false
|
||||
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
|
||||
id 'com.gradleup.shadow' version '8.3.4' apply false
|
||||
id 'com.diffplug.spotless' version '6.20.0' apply false
|
||||
id 'com.github.spotbugs' version '6.0.2' apply false
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ repositories {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
implementation "edu.wpi.first:native-utils:2025.3.0"
|
||||
implementation "edu.wpi.first:native-utils:2025.9.1"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class WPIJREArtifact extends MavenArtifact {
|
||||
|
||||
private boolean checkJreVersion = true;
|
||||
|
||||
private final String artifactLocation = "edu.wpi.first.jdk:roborio-2024:17.0.9u7-1"
|
||||
private final String artifactLocation = "edu.wpi.first.jdk:roborio-2024:17.0.9u7-3"
|
||||
|
||||
@Inject
|
||||
public WPIJREArtifact(String name, RemoteTarget target) {
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load("@rules_java//java:defs.bzl", "java_binary", "java_library")
|
||||
|
||||
cc_library(
|
||||
name = "cameraserver.static",
|
||||
srcs = glob(["src/main/native/cpp/**"]),
|
||||
hdrs = glob(["src/main/native/include/**/*"]),
|
||||
includes = [
|
||||
"cpp",
|
||||
"src/main/native/include",
|
||||
],
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cscore:cscore.static",
|
||||
"//ntcore:ntcore.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "cameraserver-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
@@ -16,10 +32,21 @@ java_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cameraserver-cpp-test",
|
||||
size = "small",
|
||||
srcs = glob(["src/test/native/**"]),
|
||||
deps = [
|
||||
":cameraserver.static",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
":cameraserver.static",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ application {
|
||||
mainClass = 'edu.wpi.Main'
|
||||
}
|
||||
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
apply plugin: 'com.gradleup.shadow'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
|
||||
@@ -14,18 +14,20 @@ macro(wpilib_target_warnings target)
|
||||
|
||||
target_compile_options(${target} PRIVATE ${WARNING_FLAGS})
|
||||
else()
|
||||
target_compile_options(
|
||||
${target}
|
||||
PRIVATE
|
||||
/wd4146
|
||||
/wd4244
|
||||
/wd4251
|
||||
/wd4267
|
||||
/wd4324
|
||||
/WX
|
||||
/D_CRT_SECURE_NO_WARNINGS
|
||||
${WPILIB_TARGET_WARNINGS}
|
||||
set(WARNING_FLAGS
|
||||
/wd4146
|
||||
/wd4244
|
||||
/wd4251
|
||||
/wd4267
|
||||
/wd4324
|
||||
/D_CRT_SECURE_NO_WARNINGS
|
||||
${WPILIB_TARGET_WARNINGS}
|
||||
)
|
||||
if(NOT NO_WERROR)
|
||||
set(WARNING_FLAGS ${WARNING_FLAGS} /WX)
|
||||
endif()
|
||||
|
||||
target_compile_options(${target} PRIVATE ${WARNING_FLAGS})
|
||||
endif()
|
||||
|
||||
# Suppress C++-specific OpenCV warning; C compiler rejects it with an error
|
||||
@@ -44,7 +46,7 @@ macro(wpilib_target_warnings target)
|
||||
|
||||
# Suppress warning "enumeration types with a fixed underlying type are a
|
||||
# Clang extension"
|
||||
if(APPLE)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C>:-Wno-fixed-enum-extension>)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,5 +1,76 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test", "objc_library")
|
||||
load("@rules_java//java:defs.bzl", "java_binary", "java_library")
|
||||
|
||||
WIN_SRCS = glob([
|
||||
"src/main/native/windows/**/*.cpp",
|
||||
"src/main/native/windows/**/*.h",
|
||||
])
|
||||
|
||||
LINUX_SRCS = glob([
|
||||
"src/main/native/linux/**/*.cpp",
|
||||
"src/main/native/linux/**/*.h",
|
||||
])
|
||||
|
||||
MAC_SRCS = glob(["src/main/native/osx/**/*.cpp"])
|
||||
|
||||
filegroup(
|
||||
name = "native-srcs",
|
||||
srcs = select({
|
||||
"@bazel_tools//src/conditions:darwin": MAC_SRCS,
|
||||
"@bazel_tools//src/conditions:windows": WIN_SRCS,
|
||||
"@rules_bzlmodrio_toolchains//constraints/combined:is_linux": LINUX_SRCS,
|
||||
}),
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "cscore-mac",
|
||||
srcs = glob([
|
||||
"src/main/native/objcpp/**/*.mm",
|
||||
"src/main/native/cpp/*.h",
|
||||
]),
|
||||
hdrs = glob([
|
||||
"src/main/native/include/**/*",
|
||||
"src/main/native/objcpp/**/*.h",
|
||||
]),
|
||||
copts = [
|
||||
"-std=c++20",
|
||||
],
|
||||
includes = [
|
||||
"src/main/native/cpp",
|
||||
"src/main/native/include",
|
||||
"src/main/native/objcpp",
|
||||
],
|
||||
tags = ["manual"],
|
||||
deps = [
|
||||
"//wpinet:wpinet.static",
|
||||
"//wpiutil:wpiutil.static",
|
||||
"@bzlmodrio-opencv//libraries/cpp/opencv",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cscore.static",
|
||||
srcs = [":native-srcs"] + glob(
|
||||
["src/main/native/cpp/**"],
|
||||
exclude = ["src/main/native/cpp/jni/**"],
|
||||
),
|
||||
hdrs = glob(["src/main/native/include/**/*"]),
|
||||
includes = [
|
||||
"src/main/native/cpp",
|
||||
"src/main/native/include",
|
||||
],
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//wpinet:wpinet.static",
|
||||
"//wpiutil:wpiutil.static",
|
||||
"@bzlmodrio-opencv//libraries/cpp/opencv",
|
||||
] + select({
|
||||
"@bazel_tools//src/conditions:darwin": [":cscore-mac"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "cscore-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
@@ -10,6 +81,24 @@ java_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cscore-cpp-test",
|
||||
size = "small",
|
||||
srcs = glob(["src/test/native/**"]),
|
||||
deps = [
|
||||
":cscore.static",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
":cscore.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "DevMain-Java",
|
||||
srcs = ["src/dev/java/edu/wpi/first/cscore/DevMain.java"],
|
||||
|
||||
@@ -185,7 +185,7 @@ model {
|
||||
lib project: ':wpinet', library: 'wpinet', linkage: 'shared'
|
||||
lib project: ':wpigui', library: 'wpigui', linkage: 'static'
|
||||
lib library: 'cscore', linkage: 'shared'
|
||||
lib project: ':thirdparty:imgui_suite', library: 'imgui', linkage: 'static'
|
||||
lib project: ':thirdparty:imgui_suite', library: 'imguiSuite', linkage: 'static'
|
||||
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
|
||||
it.buildable = false
|
||||
return
|
||||
|
||||
@@ -6,6 +6,7 @@ package edu.wpi.first.cscore;
|
||||
|
||||
import edu.wpi.first.util.PixelFormat;
|
||||
import edu.wpi.first.util.RawFrame;
|
||||
import edu.wpi.first.util.TimestampSource;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
@@ -44,7 +45,7 @@ public class CvSink extends ImageSink {
|
||||
* Create a sink for accepting OpenCV images. grabFrame() must be called on the created sink to
|
||||
* get each new image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param name Sink name (arbitrary unique identifier)
|
||||
* @param pixelFormat Source pixel format
|
||||
*/
|
||||
public CvSink(String name, PixelFormat pixelFormat) {
|
||||
@@ -220,4 +221,22 @@ public class CvSink extends ImageSink {
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last time a frame was grabbed. This uses the same time base as wpi::Now().
|
||||
*
|
||||
* @return Time in 1 us increments.
|
||||
*/
|
||||
public long getLastFrameTime() {
|
||||
return m_frame.getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time source for the timestamp the last frame was grabbed at.
|
||||
*
|
||||
* @return Time source
|
||||
*/
|
||||
public TimestampSource getLastFrameTimeSource() {
|
||||
return m_frame.getTimestampSource();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,22 @@
|
||||
|
||||
using namespace cs;
|
||||
|
||||
Frame::Frame(SourceImpl& source, std::string_view error, Time time)
|
||||
Frame::Frame(SourceImpl& source, std::string_view error, Time time,
|
||||
WPI_TimestampSource timeSrc)
|
||||
: m_impl{source.AllocFrameImpl().release()} {
|
||||
m_impl->refcount = 1;
|
||||
m_impl->error = error;
|
||||
m_impl->time = time;
|
||||
m_impl->timeSource = timeSrc;
|
||||
}
|
||||
|
||||
Frame::Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time)
|
||||
Frame::Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time,
|
||||
WPI_TimestampSource timeSrc)
|
||||
: m_impl{source.AllocFrameImpl().release()} {
|
||||
m_impl->refcount = 1;
|
||||
m_impl->error.resize(0);
|
||||
m_impl->time = time;
|
||||
m_impl->timeSource = timeSrc;
|
||||
m_impl->images.push_back(image.release());
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ class Frame {
|
||||
wpi::recursive_mutex mutex;
|
||||
std::atomic_int refcount{0};
|
||||
Time time{0};
|
||||
WPI_TimestampSource timeSource{WPI_TIMESRC_UNKNOWN};
|
||||
SourceImpl& source;
|
||||
std::string error;
|
||||
wpi::SmallVector<Image*, 4> images;
|
||||
@@ -48,9 +49,11 @@ class Frame {
|
||||
public:
|
||||
Frame() noexcept = default;
|
||||
|
||||
Frame(SourceImpl& source, std::string_view error, Time time);
|
||||
Frame(SourceImpl& source, std::string_view error, Time time,
|
||||
WPI_TimestampSource timeSrc);
|
||||
|
||||
Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time);
|
||||
Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time,
|
||||
WPI_TimestampSource timeSrc);
|
||||
|
||||
Frame(const Frame& frame) noexcept : m_impl{frame.m_impl} {
|
||||
if (m_impl) {
|
||||
@@ -75,6 +78,9 @@ class Frame {
|
||||
}
|
||||
|
||||
Time GetTime() const { return m_impl ? m_impl->time : 0; }
|
||||
WPI_TimestampSource GetTimeSource() const {
|
||||
return m_impl ? m_impl->timeSource : WPI_TIMESRC_UNKNOWN;
|
||||
}
|
||||
|
||||
std::string_view GetError() const {
|
||||
if (!m_impl) {
|
||||
|
||||
@@ -50,7 +50,7 @@ inline void NamedLog(wpi::Logger& logger, unsigned int level, const char* file,
|
||||
|
||||
#define SLOG(level, format, ...) \
|
||||
NamedLog(m_logger, level, __FILE__, __LINE__, GetName(), \
|
||||
FMT_STRING(format) __VA_OPT__(, ) __VA_ARGS__)
|
||||
format __VA_OPT__(, ) __VA_ARGS__)
|
||||
|
||||
#define SERROR(format, ...) \
|
||||
SLOG(::wpi::WPI_LOG_ERROR, format __VA_OPT__(, ) __VA_ARGS__)
|
||||
|
||||
@@ -63,6 +63,11 @@ uint64_t RawSinkImpl::GrabFrame(WPI_RawFrame& image) {
|
||||
}
|
||||
|
||||
uint64_t RawSinkImpl::GrabFrame(WPI_RawFrame& image, double timeout) {
|
||||
return GrabFrame(image, timeout, 0);
|
||||
}
|
||||
|
||||
uint64_t RawSinkImpl::GrabFrame(WPI_RawFrame& image, double timeout,
|
||||
uint64_t lastFrameTime) {
|
||||
SetEnabled(true);
|
||||
|
||||
auto source = GetSource();
|
||||
@@ -72,7 +77,7 @@ uint64_t RawSinkImpl::GrabFrame(WPI_RawFrame& image, double timeout) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto frame = source->GetNextFrame(timeout); // blocks
|
||||
auto frame = source->GetNextFrame(timeout, lastFrameTime); // blocks
|
||||
if (!frame) {
|
||||
// Bad frame; sleep for 20 ms so we don't consume all processor time.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
@@ -115,6 +120,8 @@ uint64_t RawSinkImpl::GrabFrameImpl(WPI_RawFrame& rawFrame,
|
||||
rawFrame.pixelFormat = newImage->pixelFormat;
|
||||
rawFrame.size = newImage->size();
|
||||
std::copy(newImage->data(), newImage->data() + rawFrame.size, rawFrame.data);
|
||||
rawFrame.timestamp = incomingFrame.GetTime();
|
||||
rawFrame.timestampSrc = incomingFrame.GetTimeSource();
|
||||
|
||||
return incomingFrame.GetTime();
|
||||
}
|
||||
@@ -183,6 +190,18 @@ uint64_t GrabSinkFrameTimeout(CS_Sink sink, WPI_RawFrame& image, double timeout,
|
||||
return static_cast<RawSinkImpl&>(*data->sink).GrabFrame(image, timeout);
|
||||
}
|
||||
|
||||
uint64_t GrabSinkFrameTimeoutLastTime(CS_Sink sink, WPI_RawFrame& image,
|
||||
double timeout, uint64_t lastFrameTime,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || (data->kind & SinkMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
return static_cast<RawSinkImpl&>(*data->sink)
|
||||
.GrabFrame(image, timeout, lastFrameTime);
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
extern "C" {
|
||||
@@ -209,4 +228,13 @@ uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct WPI_RawFrame* image,
|
||||
return cs::GrabSinkFrameTimeout(sink, *image, timeout, status);
|
||||
}
|
||||
|
||||
uint64_t CS_GrabRawSinkFrameTimeoutWithFrameTime(CS_Sink sink,
|
||||
struct WPI_RawFrame* image,
|
||||
double timeout,
|
||||
uint64_t lastFrameTime,
|
||||
CS_Status* status) {
|
||||
return cs::GrabSinkFrameTimeoutLastTime(sink, *image, timeout, lastFrameTime,
|
||||
status);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -34,10 +34,15 @@ class RawSinkImpl : public SinkImpl {
|
||||
|
||||
uint64_t GrabFrame(WPI_RawFrame& frame);
|
||||
uint64_t GrabFrame(WPI_RawFrame& frame, double timeout);
|
||||
// Wait for a frame with a time other than lastFrameTime
|
||||
uint64_t GrabFrame(WPI_RawFrame& frame, double timeout,
|
||||
uint64_t lastFrameTime);
|
||||
|
||||
private:
|
||||
void ThreadMain();
|
||||
|
||||
// Copies the image from incomingFrame into rawFrame, converting where
|
||||
// necessary to the resolution of rawFrame
|
||||
uint64_t GrabFrameImpl(WPI_RawFrame& rawFrame, Frame& incomingFrame);
|
||||
|
||||
std::atomic_bool m_active; // set to false to terminate threads
|
||||
|
||||
@@ -29,7 +29,7 @@ SourceImpl::SourceImpl(std::string_view name, wpi::Logger& logger,
|
||||
m_notifier(notifier),
|
||||
m_telemetry(telemetry),
|
||||
m_name{name} {
|
||||
m_frame = Frame{*this, std::string_view{}, 0};
|
||||
m_frame = Frame{*this, std::string_view{}, 0, WPI_TIMESRC_UNKNOWN};
|
||||
}
|
||||
|
||||
SourceImpl::~SourceImpl() {
|
||||
@@ -84,13 +84,19 @@ Frame SourceImpl::GetNextFrame() {
|
||||
return m_frame;
|
||||
}
|
||||
|
||||
Frame SourceImpl::GetNextFrame(double timeout) {
|
||||
Frame SourceImpl::GetNextFrame(double timeout, Frame::Time lastFrameTime) {
|
||||
std::unique_lock lock{m_frameMutex};
|
||||
auto oldTime = m_frame.GetTime();
|
||||
|
||||
if (lastFrameTime == 0) {
|
||||
lastFrameTime = m_frame.GetTime();
|
||||
}
|
||||
|
||||
// Wait unitl m_frame has a timestamp other than lastFrameTime
|
||||
if (!m_frameCv.wait_for(
|
||||
lock, std::chrono::milliseconds(static_cast<int>(timeout * 1000)),
|
||||
[=, this] { return m_frame.GetTime() != oldTime; })) {
|
||||
m_frame = Frame{*this, "timed out getting frame", wpi::Now()};
|
||||
[=, this] { return m_frame.GetTime() != lastFrameTime; })) {
|
||||
m_frame = Frame{*this, "timed out getting frame", wpi::Now(),
|
||||
WPI_TIMESRC_UNKNOWN};
|
||||
}
|
||||
return m_frame;
|
||||
}
|
||||
@@ -98,7 +104,7 @@ Frame SourceImpl::GetNextFrame(double timeout) {
|
||||
void SourceImpl::Wakeup() {
|
||||
{
|
||||
std::scoped_lock lock{m_frameMutex};
|
||||
m_frame = Frame{*this, std::string_view{}, 0};
|
||||
m_frame = Frame{*this, std::string_view{}, 0, WPI_TIMESRC_UNKNOWN};
|
||||
}
|
||||
m_frameCv.notify_all();
|
||||
}
|
||||
@@ -458,7 +464,8 @@ std::unique_ptr<Image> SourceImpl::AllocImage(
|
||||
}
|
||||
|
||||
void SourceImpl::PutFrame(VideoMode::PixelFormat pixelFormat, int width,
|
||||
int height, std::string_view data, Frame::Time time) {
|
||||
int height, std::string_view data, Frame::Time time,
|
||||
WPI_TimestampSource timeSrc) {
|
||||
if (pixelFormat == VideoMode::PixelFormat::kBGRA) {
|
||||
// Write BGRA as BGR to save a copy
|
||||
auto image =
|
||||
@@ -475,10 +482,11 @@ void SourceImpl::PutFrame(VideoMode::PixelFormat pixelFormat, int width,
|
||||
fmt::ptr(data.data()), data.size());
|
||||
std::memcpy(image->data(), data.data(), data.size());
|
||||
|
||||
PutFrame(std::move(image), time);
|
||||
PutFrame(std::move(image), time, timeSrc);
|
||||
}
|
||||
|
||||
void SourceImpl::PutFrame(std::unique_ptr<Image> image, Frame::Time time) {
|
||||
void SourceImpl::PutFrame(std::unique_ptr<Image> image, Frame::Time time,
|
||||
WPI_TimestampSource timeSrc) {
|
||||
// Update telemetry
|
||||
m_telemetry.RecordSourceFrames(*this, 1);
|
||||
m_telemetry.RecordSourceBytes(*this, static_cast<int>(image->size()));
|
||||
@@ -486,7 +494,7 @@ void SourceImpl::PutFrame(std::unique_ptr<Image> image, Frame::Time time) {
|
||||
// Update frame
|
||||
{
|
||||
std::scoped_lock lock{m_frameMutex};
|
||||
m_frame = Frame{*this, std::move(image), time};
|
||||
m_frame = Frame{*this, std::move(image), time, timeSrc};
|
||||
}
|
||||
|
||||
// Signal listeners
|
||||
@@ -497,7 +505,7 @@ void SourceImpl::PutError(std::string_view msg, Frame::Time time) {
|
||||
// Update frame
|
||||
{
|
||||
std::scoped_lock lock{m_frameMutex};
|
||||
m_frame = Frame{*this, msg, time};
|
||||
m_frame = Frame{*this, msg, time, WPI_TIMESRC_UNKNOWN};
|
||||
}
|
||||
|
||||
// Signal listeners
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/RawFrame.h>
|
||||
#include <wpi/condition_variable.h>
|
||||
#include <wpi/json_fwd.h>
|
||||
#include <wpi/mutex.h>
|
||||
@@ -98,7 +99,8 @@ class SourceImpl : public PropertyContainer {
|
||||
|
||||
// Blocking function that waits for the next frame and returns it (with
|
||||
// timeout in seconds). If timeout expires, returns empty frame.
|
||||
Frame GetNextFrame(double timeout);
|
||||
// If lastFrameTime==0, uses m_frame.GetTime() for lastFrameTime
|
||||
Frame GetNextFrame(double timeout, Frame::Time lastFrameTime = 0);
|
||||
|
||||
// Force a wakeup of all GetNextFrame() callers by sending an empty frame.
|
||||
void Wakeup();
|
||||
@@ -140,8 +142,10 @@ class SourceImpl : public PropertyContainer {
|
||||
std::string_view valueStr) override;
|
||||
|
||||
void PutFrame(VideoMode::PixelFormat pixelFormat, int width, int height,
|
||||
std::string_view data, Frame::Time time);
|
||||
void PutFrame(std::unique_ptr<Image> image, Frame::Time time);
|
||||
std::string_view data, Frame::Time time,
|
||||
WPI_TimestampSource timeSrc = WPI_TIMESRC_FRAME_DEQUEUE);
|
||||
void PutFrame(std::unique_ptr<Image> image, Frame::Time time,
|
||||
WPI_TimestampSource timeSrc = WPI_TIMESRC_FRAME_DEQUEUE);
|
||||
void PutError(std::string_view msg, Frame::Time time);
|
||||
|
||||
// Notification functions for corresponding atomics
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <functional>
|
||||
|
||||
#include <opencv2/core/mat.hpp>
|
||||
#include <wpi/RawFrame.h>
|
||||
|
||||
#include "cscore_oo.h"
|
||||
#include "cscore_raw.h"
|
||||
@@ -151,6 +152,44 @@ class CvSink : public ImageSink {
|
||||
[[nodiscard]]
|
||||
uint64_t GrabFrameNoTimeoutDirect(cv::Mat& image);
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after timeout seconds.
|
||||
* The provided image will have the pixelFormat this class was constructed
|
||||
* with. The data is backed by data in the CvSink. It will be invalidated by
|
||||
* any grabFrame*() call on the sink.
|
||||
*
|
||||
* <p>If lastFrameTime is provided and non-zero, the sink will fill image with
|
||||
* the first frame from the source that is not equal to lastFrameTime. If
|
||||
* lastFrameTime is zero, the time of the current frame owned by the CvSource
|
||||
* is used, and this function will block until the connected CvSource provides
|
||||
* a new frame.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
uint64_t GrabFrameDirectLastTime(cv::Mat& image, uint64_t lastFrameTime,
|
||||
double timeout = 0.225);
|
||||
|
||||
/**
|
||||
* Get the last time a frame was grabbed. This uses the same time base as
|
||||
* wpi::Now().
|
||||
*
|
||||
* @return Time in 1 us increments.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
uint64_t LastFrameTime();
|
||||
|
||||
/**
|
||||
* Get the time source for the timestamp the last frame was grabbed at.
|
||||
*
|
||||
* @return Time source
|
||||
*/
|
||||
[[nodiscard]]
|
||||
WPI_TimestampSource LastFrameTimeSource();
|
||||
|
||||
private:
|
||||
constexpr int GetCvFormat(WPI_PixelFormat pixelFormat);
|
||||
|
||||
@@ -365,6 +404,33 @@ inline uint64_t CvSink::GrabFrameNoTimeoutDirect(cv::Mat& image) {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
inline uint64_t CvSink::GrabFrameDirectLastTime(cv::Mat& image,
|
||||
uint64_t lastFrameTime,
|
||||
double timeout) {
|
||||
rawFrame.height = 0;
|
||||
rawFrame.width = 0;
|
||||
rawFrame.stride = 0;
|
||||
rawFrame.pixelFormat = pixelFormat;
|
||||
auto timestamp = GrabSinkFrameTimeoutLastTime(m_handle, rawFrame, timeout,
|
||||
lastFrameTime, &m_status);
|
||||
if (m_status != CS_OK) {
|
||||
return 0;
|
||||
}
|
||||
image =
|
||||
cv::Mat{rawFrame.height, rawFrame.width,
|
||||
GetCvFormat(static_cast<WPI_PixelFormat>(rawFrame.pixelFormat)),
|
||||
rawFrame.data, static_cast<size_t>(rawFrame.stride)};
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
inline uint64_t CvSink::LastFrameTime() {
|
||||
return rawFrame.timestamp;
|
||||
}
|
||||
|
||||
inline WPI_TimestampSource CvSink::LastFrameTimeSource() {
|
||||
return static_cast<WPI_TimestampSource>(rawFrame.timestampSrc);
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_CSCORE_CV_H_
|
||||
|
||||
@@ -27,6 +27,11 @@ uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct WPI_RawFrame* rawImage,
|
||||
CS_Status* status);
|
||||
uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct WPI_RawFrame* rawImage,
|
||||
double timeout, CS_Status* status);
|
||||
uint64_t CS_GrabRawSinkFrameTimeoutWithFrameTime(CS_Sink sink,
|
||||
struct WPI_RawFrame* rawImage,
|
||||
double timeout,
|
||||
uint64_t lastFrameTime,
|
||||
CS_Status* status);
|
||||
|
||||
CS_Sink CS_CreateRawSink(const struct WPI_String* name, CS_Bool isCv,
|
||||
CS_Status* status);
|
||||
@@ -67,6 +72,9 @@ void PutSourceFrame(CS_Source source, const WPI_RawFrame& image,
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, WPI_RawFrame& image, CS_Status* status);
|
||||
uint64_t GrabSinkFrameTimeout(CS_Sink sink, WPI_RawFrame& image, double timeout,
|
||||
CS_Status* status);
|
||||
uint64_t GrabSinkFrameTimeoutLastTime(CS_Sink sink, WPI_RawFrame& image,
|
||||
double timeout, uint64_t lastFrameTime,
|
||||
CS_Status* status);
|
||||
|
||||
/**
|
||||
* A source for user code to provide video frames as raw bytes.
|
||||
@@ -163,6 +171,24 @@ class RawSink : public ImageSink {
|
||||
*/
|
||||
[[nodiscard]]
|
||||
uint64_t GrabFrameNoTimeout(wpi::RawFrame& image) const;
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. May block forever.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* <p>If lastFrameTime is provided and non-zero, the sink will fill image with
|
||||
* the first frame from the source that is not equal to lastFrameTime. If
|
||||
* lastFrameTime is zero, the time of the current frame owned by the CvSource
|
||||
* is used, and this function will block until the connected CvSource provides
|
||||
* a new frame.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
uint64_t GrabFrameLastTime(wpi::RawFrame& image, uint64_t lastFrameTime,
|
||||
double timeout = 0.225) const;
|
||||
};
|
||||
|
||||
inline RawSource::RawSource(std::string_view name, const VideoMode& mode) {
|
||||
@@ -199,6 +225,14 @@ inline uint64_t RawSink::GrabFrameNoTimeout(wpi::RawFrame& image) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrame(m_handle, image, &m_status);
|
||||
}
|
||||
|
||||
inline uint64_t RawSink::GrabFrameLastTime(wpi::RawFrame& image,
|
||||
uint64_t lastFrameTime,
|
||||
double timeout) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrameTimeoutLastTime(m_handle, image, timeout, lastFrameTime,
|
||||
&m_status);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
} // namespace cs
|
||||
|
||||
@@ -555,8 +555,51 @@ void UsbCameraImpl::CameraThreadMain() {
|
||||
good = false;
|
||||
}
|
||||
if (good) {
|
||||
Frame::Time frameTime{wpi::Now()};
|
||||
WPI_TimestampSource timeSource{WPI_TIMESRC_FRAME_DEQUEUE};
|
||||
|
||||
// check the timestamp time
|
||||
auto tsFlags = buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MASK;
|
||||
SDEBUG4("Flags {}", tsFlags);
|
||||
if (tsFlags == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN) {
|
||||
SDEBUG4("Got unknown time for frame - default to wpi::Now");
|
||||
} else if (tsFlags == V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) {
|
||||
SDEBUG4("Got valid monotonic time for frame");
|
||||
// we can't go directly to frametime, since the rest of cscore
|
||||
// expects us to use wpi::Now, which is in an arbitrary timebase
|
||||
// (see timestamp.cpp). Best I can do is (approximately) translate
|
||||
// between timebases
|
||||
|
||||
// grab current time in the same timebase as buf.timestamp
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
||||
int64_t nowTime = {ts.tv_sec * 1'000'000 + ts.tv_nsec / 1000};
|
||||
int64_t bufTime = {buf.timestamp.tv_sec * 1'000'000 +
|
||||
buf.timestamp.tv_usec};
|
||||
// And offset frameTime by the latency
|
||||
int64_t offset{nowTime - bufTime};
|
||||
frameTime -= offset;
|
||||
|
||||
// Figure out the timestamp's source
|
||||
int tsrcFlags = buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
|
||||
if (tsrcFlags == V4L2_BUF_FLAG_TSTAMP_SRC_EOF) {
|
||||
timeSource = WPI_TIMESRC_V4L_EOF;
|
||||
} else if (tsrcFlags == V4L2_BUF_FLAG_TSTAMP_SRC_SOE) {
|
||||
timeSource = WPI_TIMESRC_V4L_SOE;
|
||||
} else {
|
||||
timeSource = WPI_TIMESRC_UNKNOWN;
|
||||
}
|
||||
SDEBUG4("Frame was {} uS old, flags {}, source {}", offset,
|
||||
tsrcFlags, static_cast<int>(timeSource));
|
||||
} else {
|
||||
// Can't do anything if we can't access the clock, leave default
|
||||
}
|
||||
} else if (tsFlags == V4L2_BUF_FLAG_TIMESTAMP_COPY) {
|
||||
SDEBUG4("Got valid copy time for frame - default to wpi::Now");
|
||||
}
|
||||
|
||||
PutFrame(static_cast<VideoMode::PixelFormat>(m_mode.pixelFormat),
|
||||
width, height, image, wpi::Now()); // TODO: time
|
||||
width, height, image, frameTime, timeSource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ inline void NamedLog(UsbCameraImplObjc* objc, unsigned int level,
|
||||
|
||||
#define OBJCLOG(level, format, ...) \
|
||||
NamedLog(self, level, __FILE__, __LINE__, \
|
||||
FMT_STRING(format) __VA_OPT__(, ) __VA_ARGS__)
|
||||
format __VA_OPT__(, ) __VA_ARGS__)
|
||||
|
||||
#define OBJCERROR(format, ...) \
|
||||
OBJCLOG(::wpi::WPI_LOG_ERROR, format __VA_OPT__(, ) __VA_ARGS__)
|
||||
|
||||
@@ -101,7 +101,7 @@ model {
|
||||
lib project: ':glass', library: 'glass', linkage: 'static'
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
|
||||
lib project: ':wpigui', library: 'wpigui', linkage: 'static'
|
||||
lib project: ':thirdparty:imgui_suite', library: 'imgui', linkage: 'static'
|
||||
lib project: ':thirdparty:imgui_suite', library: 'imguiSuite', linkage: 'static'
|
||||
nativeUtils.useRequiredLibrary(it, 'libssh')
|
||||
if (it.targetPlatform.operatingSystem.isWindows()) {
|
||||
it.linker.args << 'Gdi32.lib' << 'Shell32.lib' << 'd3d11.lib' << 'd3dcompiler.lib'
|
||||
|
||||
@@ -5,4 +5,4 @@ include(CompileWarnings)
|
||||
file(GLOB developerRobotCpp_src src/main/native/cpp/*.cpp)
|
||||
|
||||
add_executable(developerRobotCpp ${developerRobotCpp_src})
|
||||
target_link_libraries(developerRobotCpp wpilibc)
|
||||
target_link_libraries(developerRobotCpp wpilibc wpilibNewCommands apriltag)
|
||||
|
||||
@@ -9,7 +9,12 @@ This command builds everything.
|
||||
|
||||
## Simulation
|
||||
|
||||
This command runs the C++ subproject on desktop.
|
||||
This command runs the Java project on desktop.
|
||||
```bash
|
||||
./gradlew developerRobot:run
|
||||
```
|
||||
|
||||
This command runs the C++ project on desktop.
|
||||
```bash
|
||||
./gradlew developerRobot:runCpp
|
||||
```
|
||||
|
||||
@@ -35,7 +35,7 @@ application {
|
||||
mainClass = 'frc.robot.Main'
|
||||
}
|
||||
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
apply plugin: 'com.gradleup.shadow'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
@@ -54,6 +54,9 @@ dependencies {
|
||||
implementation project(':cameraserver')
|
||||
implementation project(':wpilibNewCommands')
|
||||
implementation project(':apriltag')
|
||||
implementation project(':wpiunits')
|
||||
implementation project(':epilogue-runtime')
|
||||
annotationProcessor project(':epilogue-processor')
|
||||
}
|
||||
|
||||
tasks.withType(com.github.spotbugs.snom.SpotBugsTask).configureEach {
|
||||
@@ -139,6 +142,19 @@ deploy {
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent the eclipse compiler (used by the VS Code extension for intellisense and debugging)
|
||||
// from generating bad class files from annotation processors like Epilogue
|
||||
eclipse {
|
||||
classpath {
|
||||
containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
|
||||
file.whenMerged { cp ->
|
||||
def entries = cp.entries;
|
||||
def src = new org.gradle.plugins.ide.eclipse.model.SourceFolder('build/generated/sources/annotationProcessor/java/main/', null)
|
||||
entries.add(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('deployJava') {
|
||||
try {
|
||||
dependsOn tasks.named('deployjreroborio')
|
||||
|
||||
22
epilogue-processor/BUILD.bazel
Normal file
22
epilogue-processor/BUILD.bazel
Normal file
@@ -0,0 +1,22 @@
|
||||
load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
|
||||
|
||||
java_library(
|
||||
name = "processor",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
visibility = ["//visibility:public"],
|
||||
runtime_deps = [
|
||||
"//wpilibNewCommands:wpilibNewCommands-java",
|
||||
],
|
||||
deps = [
|
||||
"//epilogue-runtime:epilogue",
|
||||
],
|
||||
)
|
||||
|
||||
java_plugin(
|
||||
name = "plugin",
|
||||
processor_class = "edu.wpi.first.epilogue.processor.AnnotationProcessor",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":processor",
|
||||
],
|
||||
)
|
||||
@@ -11,9 +11,12 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
@@ -65,7 +68,9 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
customLoggers.putAll(processCustomLoggers(roundEnv, customLogger));
|
||||
});
|
||||
|
||||
// Get all root types (classes and interfaces), excluding packages and modules
|
||||
roundEnv.getRootElements().stream()
|
||||
.filter(e -> e instanceof TypeElement)
|
||||
.filter(
|
||||
e ->
|
||||
processingEnv
|
||||
@@ -86,19 +91,19 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Custom logger classes should have a @CustomLoggerFor annotation",
|
||||
"[EPILOGUE] Custom logger classes should have a @CustomLoggerFor annotation",
|
||||
e);
|
||||
});
|
||||
|
||||
var loggedTypes = getLoggedTypes(roundEnv);
|
||||
|
||||
// Handlers are declared in order of priority. If an element could be logged in more than one
|
||||
// way (eg a class implements both Sendable and StructSerializable), the order of the handlers
|
||||
// in this list will determine how it gets logged.
|
||||
m_handlers =
|
||||
List.of(
|
||||
new LoggableHandler(
|
||||
processingEnv,
|
||||
roundEnv.getElementsAnnotatedWith(
|
||||
Logged.class)), // prioritize epilogue logging over Sendable
|
||||
processingEnv, loggedTypes), // prioritize epilogue logging over Sendable
|
||||
new ConfiguredLoggerHandler(
|
||||
processingEnv, customLoggers), // then customized logging configs
|
||||
new ArrayHandler(processingEnv),
|
||||
@@ -118,12 +123,39 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.findAny()
|
||||
.ifPresent(
|
||||
epilogue -> {
|
||||
processEpilogue(roundEnv, epilogue);
|
||||
processEpilogue(roundEnv, epilogue, loggedTypes);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of all loggable types in the compilation unit. A type is considered loggable if it
|
||||
* is directly annotated with {@code @Logged} or contains a field or method with a {@code @Logged}
|
||||
* annotation.
|
||||
*
|
||||
* @param roundEnv the compilation round environment
|
||||
* @return the set of all loggable types
|
||||
*/
|
||||
private Set<TypeElement> getLoggedTypes(RoundEnvironment roundEnv) {
|
||||
// Fetches everything annotated with @Logged; classes, methods, values, etc.
|
||||
var annotatedElements = roundEnv.getElementsAnnotatedWith(Logged.class);
|
||||
return Stream.concat(
|
||||
// 1. All type elements (classes, interfaces, or enums) with the @Logged annotation
|
||||
annotatedElements.stream()
|
||||
.filter(e -> e instanceof TypeElement)
|
||||
.map(e -> (TypeElement) e),
|
||||
// 2. All type elements containing a field or method with the @Logged annotation
|
||||
annotatedElements.stream()
|
||||
.filter(e -> e instanceof VariableElement || e instanceof ExecutableElement)
|
||||
.map(Element::getEnclosingElement)
|
||||
.filter(e -> e instanceof TypeElement)
|
||||
.map(e -> (TypeElement) e))
|
||||
.sorted(Comparator.comparing(e -> e.getSimpleName().toString()))
|
||||
.collect(
|
||||
Collectors.toCollection(LinkedHashSet::new)); // Collect to a set to avoid duplicates
|
||||
}
|
||||
|
||||
private boolean validateFields(Set<? extends Element> annotatedElements) {
|
||||
var fields =
|
||||
annotatedElements.stream()
|
||||
@@ -237,12 +269,18 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
return false;
|
||||
}
|
||||
|
||||
processingEnv
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.NOTE,
|
||||
"[EPILOGUE] Excluded from logs because " + type + " is not a loggable data type",
|
||||
element);
|
||||
var classConfig = element.getEnclosingElement().getAnnotation(Logged.class);
|
||||
|
||||
if (classConfig == null || classConfig.warnForNonLoggableTypes()) {
|
||||
// Not loggable and not explicitly opted out of logging; print a warning message
|
||||
processingEnv
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.NOTE,
|
||||
"[EPILOGUE] Excluded from logs because " + type + " is not a loggable data type",
|
||||
element);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -284,7 +322,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Logger classes must have a public no-argument constructor",
|
||||
"[EPILOGUE] Logger classes must have a public no-argument constructor",
|
||||
annotatedElement);
|
||||
continue;
|
||||
}
|
||||
@@ -306,7 +344,17 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Multiple custom loggers detected for type " + targetType,
|
||||
"[EPILOGUE] Multiple custom loggers detected for type " + targetType,
|
||||
annotatedElement);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (annotatedElement instanceof TypeElement t && !t.getTypeParameters().isEmpty()) {
|
||||
processingEnv
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"[EPILOGUE] Custom logger classes cannot take generic type arguments",
|
||||
annotatedElement);
|
||||
continue;
|
||||
}
|
||||
@@ -318,7 +366,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Not a subclass of ClassSpecificLogger<" + targetType + ">",
|
||||
"[EPILOGUE] Not a subclass of ClassSpecificLogger<" + targetType + ">",
|
||||
annotatedElement);
|
||||
continue;
|
||||
}
|
||||
@@ -330,7 +378,8 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
return customLoggers;
|
||||
}
|
||||
|
||||
private void processEpilogue(RoundEnvironment roundEnv, TypeElement epilogueAnnotation) {
|
||||
private void processEpilogue(
|
||||
RoundEnvironment roundEnv, TypeElement epilogueAnnotation, Set<TypeElement> loggedTypes) {
|
||||
var annotatedElements = roundEnv.getElementsAnnotatedWith(epilogueAnnotation);
|
||||
|
||||
List<String> loggerClassNames = new ArrayList<>();
|
||||
@@ -348,12 +397,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
var classes =
|
||||
annotatedElements.stream()
|
||||
.filter(e -> e instanceof TypeElement)
|
||||
.map(e -> (TypeElement) e)
|
||||
.toList();
|
||||
for (TypeElement clazz : classes) {
|
||||
for (TypeElement clazz : loggedTypes) {
|
||||
try {
|
||||
warnOfNonLoggableElements(clazz);
|
||||
m_loggerGenerator.writeLoggerFile(clazz);
|
||||
@@ -368,7 +412,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"Could not write logger file for " + clazz.getQualifiedName(),
|
||||
"[EPILOGUE] Could not write logger file for " + clazz.getQualifiedName(),
|
||||
clazz);
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
@@ -381,7 +425,7 @@ public class AnnotationProcessor extends AbstractProcessor {
|
||||
|
||||
private void warnOfNonLoggableElements(TypeElement clazz) {
|
||||
var config = clazz.getAnnotation(Logged.class);
|
||||
if (config.strategy() == Logged.Strategy.OPT_IN) {
|
||||
if (config == null || config.strategy() == Logged.Strategy.OPT_IN) {
|
||||
// field and method validations will have already checked everything
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class ArrayHandler extends ElementHandler {
|
||||
|
||||
if (m_structHandler.isLoggableType(componentType)) {
|
||||
// Struct arrays need to pass in the struct serializer
|
||||
return "dataLogger.log(\""
|
||||
return "backend.log(\""
|
||||
+ loggedName(element)
|
||||
+ "\", "
|
||||
+ elementAccess(element)
|
||||
@@ -69,7 +69,7 @@ public class ArrayHandler extends ElementHandler {
|
||||
+ ")";
|
||||
} else {
|
||||
// Primitive or string array
|
||||
return "dataLogger.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
return "backend.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class CollectionHandler extends ElementHandler {
|
||||
var componentType = ((DeclaredType) dataType).getTypeArguments().get(0);
|
||||
|
||||
if (m_structHandler.isLoggableType(componentType)) {
|
||||
return "dataLogger.log(\""
|
||||
return "backend.log(\""
|
||||
+ loggedName(element)
|
||||
+ "\", "
|
||||
+ elementAccess(element)
|
||||
@@ -51,7 +51,7 @@ public class CollectionHandler extends ElementHandler {
|
||||
+ m_structHandler.structAccess(componentType)
|
||||
+ ")";
|
||||
} else {
|
||||
return "dataLogger.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
return "backend.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,17 +22,26 @@ public class ConfiguredLoggerHandler extends ElementHandler {
|
||||
|
||||
@Override
|
||||
public boolean isLoggable(Element element) {
|
||||
return m_customLoggers.containsKey(dataType(element));
|
||||
return m_customLoggers.keySet().stream()
|
||||
.anyMatch(m -> m_processingEnv.getTypeUtils().isAssignable(dataType(element), m));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String logInvocation(Element element) {
|
||||
var dataType = dataType(element);
|
||||
var loggerType = m_customLoggers.get(dataType);
|
||||
var loggerType =
|
||||
m_customLoggers.entrySet().stream()
|
||||
.filter(
|
||||
e -> {
|
||||
return m_processingEnv.getTypeUtils().isAssignable(dataType, e.getKey());
|
||||
})
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.getValue();
|
||||
|
||||
return "Epilogue."
|
||||
+ StringUtils.lowerCamelCase(loggerType.asElement().getSimpleName())
|
||||
+ ".tryUpdate(dataLogger.getSubLogger(\""
|
||||
+ ".tryUpdate(backend.getNested(\""
|
||||
+ loggedName(element)
|
||||
+ "\"), "
|
||||
+ elementAccess(element)
|
||||
|
||||
@@ -6,7 +6,7 @@ package edu.wpi.first.epilogue.processor;
|
||||
|
||||
import edu.wpi.first.epilogue.Logged;
|
||||
import edu.wpi.first.epilogue.logging.ClassSpecificLogger;
|
||||
import edu.wpi.first.epilogue.logging.DataLogger;
|
||||
import edu.wpi.first.epilogue.logging.EpilogueBackend;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
@@ -127,8 +127,10 @@ public abstract class ElementHandler {
|
||||
|
||||
private static String fieldAccess(VariableElement field) {
|
||||
if (field.getModifiers().contains(Modifier.PRIVATE)) {
|
||||
// (com.example.Foo) $fooField.get(object)
|
||||
return "(" + field.asType() + ") $" + field.getSimpleName() + ".get(object)";
|
||||
// ((com.example.Foo) $fooField.get(object))
|
||||
// Extra parentheses so cast evaluates before appended methods
|
||||
// (e.g. when appending .getAsDouble())
|
||||
return "((" + field.asType() + ") $" + field.getSimpleName() + ".get(object))";
|
||||
} else {
|
||||
// object.fooField
|
||||
return "object." + field.getSimpleName();
|
||||
@@ -157,7 +159,7 @@ public abstract class ElementHandler {
|
||||
/**
|
||||
* Generates a code snippet to place in a generated logger file to log the value of a field or
|
||||
* method. Log invocations are placed in a generated implementation of {@link
|
||||
* ClassSpecificLogger#update(DataLogger, Object)}, with access to the data logger and logged
|
||||
* ClassSpecificLogger#update(EpilogueBackend, Object)}, with access to the backend and logged
|
||||
* object passed to the method call.
|
||||
*
|
||||
* @param element the field or method element to generate the logger call for
|
||||
|
||||
@@ -28,6 +28,6 @@ public class EnumHandler extends ElementHandler {
|
||||
|
||||
@Override
|
||||
public String logInvocation(Element element) {
|
||||
return "dataLogger.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
return "backend.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ public class EpilogueGenerator {
|
||||
out.println("import static edu.wpi.first.units.Units.Seconds;");
|
||||
out.println();
|
||||
|
||||
out.println("import edu.wpi.first.hal.FRCNetComm;");
|
||||
out.println("import edu.wpi.first.hal.HAL;");
|
||||
out.println();
|
||||
|
||||
loggerClassNames.stream()
|
||||
.sorted()
|
||||
.forEach(
|
||||
@@ -80,6 +84,18 @@ public class EpilogueGenerator {
|
||||
out.println();
|
||||
|
||||
out.println("public final class Epilogue {");
|
||||
|
||||
// Usage reporting
|
||||
out.println(
|
||||
"""
|
||||
static {
|
||||
HAL.report(
|
||||
FRCNetComm.tResourceType.kResourceType_LoggingFramework,
|
||||
FRCNetComm.tInstances.kLoggingFramework_Epilogue
|
||||
);
|
||||
}
|
||||
""");
|
||||
|
||||
out.println(
|
||||
" private static final EpilogueConfiguration config = new EpilogueConfiguration();");
|
||||
out.println();
|
||||
@@ -154,9 +170,9 @@ public class EpilogueGenerator {
|
||||
out.println(
|
||||
" "
|
||||
+ StringUtils.loggerFieldName(mainRobotClass)
|
||||
+ ".tryUpdate(config.dataLogger.getSubLogger(config.root), robot, config.errorHandler);");
|
||||
+ ".tryUpdate(config.backend.getNested(config.root), robot, config.errorHandler);");
|
||||
out.println(
|
||||
" config.dataLogger.log(\"Epilogue/Stats/Last Run\", (System.nanoTime() - start) / 1e6);");
|
||||
" config.backend.log(\"Epilogue/Stats/Last Run\", (System.nanoTime() - start) / 1e6);");
|
||||
out.println(" }");
|
||||
|
||||
out.println();
|
||||
|
||||
@@ -15,7 +15,6 @@ import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
@@ -35,10 +34,8 @@ public class LoggableHandler extends ElementHandler {
|
||||
|
||||
@Override
|
||||
public boolean isLoggable(Element element) {
|
||||
var dataType = dataType(element);
|
||||
return dataType.getAnnotation(Logged.class) != null
|
||||
|| dataType instanceof DeclaredType decl
|
||||
&& decl.asElement().getAnnotation(Logged.class) != null;
|
||||
return m_processingEnv.getTypeUtils().asElement(dataType(element)) instanceof TypeElement t
|
||||
&& m_loggedTypes.contains(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,7 +158,7 @@ public class LoggableHandler extends ElementHandler {
|
||||
}
|
||||
|
||||
private String generateLoggerCall(Element element, TypeElement type, String elementReference) {
|
||||
return ("Epilogue.%s.tryUpdate(dataLogger.getSubLogger(\"%s\"), %s, "
|
||||
return ("Epilogue.%s.tryUpdate(backend.getNested(\"%s\"), %s, "
|
||||
+ "Epilogue.getConfig().errorHandler)")
|
||||
.formatted(StringUtils.loggerFieldName(type), loggedName(element), elementReference);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ import edu.wpi.first.epilogue.Logged;
|
||||
import edu.wpi.first.epilogue.NotLogged;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -29,6 +32,7 @@ import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.Name;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.tools.Diagnostic;
|
||||
@@ -40,6 +44,40 @@ public class LoggerGenerator {
|
||||
private final ProcessingEnvironment m_processingEnv;
|
||||
private final List<ElementHandler> m_handlers;
|
||||
|
||||
@SuppressWarnings("BadAnnotationImplementation")
|
||||
private final Logged m_defaultConfig =
|
||||
new Logged() {
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Logged.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Strategy strategy() {
|
||||
return Strategy.OPT_IN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Importance importance() {
|
||||
return Importance.DEBUG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Naming defaultNaming() {
|
||||
return Naming.USE_CODE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean warnForNonLoggableTypes() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public LoggerGenerator(ProcessingEnvironment processingEnv, List<ElementHandler> handlers) {
|
||||
this.m_processingEnv = processingEnv;
|
||||
this.m_handlers = handlers;
|
||||
@@ -73,6 +111,9 @@ public class LoggerGenerator {
|
||||
*/
|
||||
public void writeLoggerFile(TypeElement clazz) throws IOException {
|
||||
var config = clazz.getAnnotation(Logged.class);
|
||||
if (config == null) {
|
||||
config = m_defaultConfig;
|
||||
}
|
||||
boolean requireExplicitOptIn = config.strategy() == Logged.Strategy.OPT_IN;
|
||||
|
||||
Predicate<Element> notSkipped = LoggerGenerator::isNotSkipped;
|
||||
@@ -150,36 +191,28 @@ public class LoggerGenerator {
|
||||
}
|
||||
});
|
||||
|
||||
writeLoggerFile(clazz.getQualifiedName().toString(), config, fieldsToLog, methodsToLog);
|
||||
writeLoggerFile(clazz, config, fieldsToLog, methodsToLog);
|
||||
}
|
||||
|
||||
private void writeLoggerFile(
|
||||
String className,
|
||||
TypeElement clazz,
|
||||
Logged classConfig,
|
||||
List<VariableElement> loggableFields,
|
||||
List<ExecutableElement> loggableMethods)
|
||||
throws IOException {
|
||||
String packageName = null;
|
||||
int lastDot = className.lastIndexOf('.');
|
||||
if (lastDot > 0) {
|
||||
packageName = className.substring(0, lastDot);
|
||||
// Walk nesting levels, to support inner classes
|
||||
Deque<String> nesting = new ArrayDeque<>();
|
||||
Element enclosing = clazz.getEnclosingElement();
|
||||
while (!(enclosing instanceof PackageElement p)) {
|
||||
nesting.addFirst(enclosing.getSimpleName().toString());
|
||||
enclosing = enclosing.getEnclosingElement();
|
||||
}
|
||||
String packageName = p.getQualifiedName().toString();
|
||||
nesting.addLast(clazz.getSimpleName().toString());
|
||||
String simpleClassName = String.join(".", nesting);
|
||||
|
||||
String simpleClassName = StringUtils.simpleName(className);
|
||||
String loggerClassName = className + "Logger";
|
||||
String loggerSimpleClassName = loggerClassName.substring(lastDot + 1);
|
||||
|
||||
// Use the name on the class config to set the generated logger names
|
||||
// This helps to avoid naming conflicts
|
||||
if (!classConfig.name().isBlank()) {
|
||||
loggerSimpleClassName =
|
||||
StringUtils.capitalize(classConfig.name().replaceAll(" ", "")) + "Logger";
|
||||
if (lastDot > 0) {
|
||||
loggerClassName = packageName + "." + loggerSimpleClassName;
|
||||
} else {
|
||||
loggerClassName = loggerSimpleClassName;
|
||||
}
|
||||
}
|
||||
String loggerClassName = StringUtils.loggerClassName(clazz);
|
||||
String loggerSimpleClassName = StringUtils.simpleName(loggerClassName);
|
||||
|
||||
var loggerFile = m_processingEnv.getFiler().createSourceFile(loggerClassName);
|
||||
|
||||
@@ -197,7 +230,7 @@ public class LoggerGenerator {
|
||||
out.println("import edu.wpi.first.epilogue.Logged;");
|
||||
out.println("import edu.wpi.first.epilogue.Epilogue;");
|
||||
out.println("import edu.wpi.first.epilogue.logging.ClassSpecificLogger;");
|
||||
out.println("import edu.wpi.first.epilogue.logging.DataLogger;");
|
||||
out.println("import edu.wpi.first.epilogue.logging.EpilogueBackend;");
|
||||
if (requiresVarHandles) {
|
||||
out.println("import java.lang.invoke.MethodHandles;");
|
||||
out.println("import java.lang.invoke.VarHandle;");
|
||||
@@ -220,13 +253,13 @@ public class LoggerGenerator {
|
||||
}
|
||||
out.println();
|
||||
|
||||
var clazz = simpleClassName + ".class";
|
||||
var classReference = simpleClassName + ".class";
|
||||
|
||||
out.println(" static {");
|
||||
out.println(" try {");
|
||||
out.println(
|
||||
" var lookup = MethodHandles.privateLookupIn("
|
||||
+ clazz
|
||||
+ classReference
|
||||
+ ", MethodHandles.lookup());");
|
||||
|
||||
for (var privateField : privateFields) {
|
||||
@@ -235,7 +268,7 @@ public class LoggerGenerator {
|
||||
" $"
|
||||
+ fieldName
|
||||
+ " = lookup.findVarHandle("
|
||||
+ clazz
|
||||
+ classReference
|
||||
+ ", \""
|
||||
+ fieldName
|
||||
+ "\", "
|
||||
@@ -258,9 +291,10 @@ public class LoggerGenerator {
|
||||
out.println();
|
||||
|
||||
// @Override
|
||||
// public void update(DataLogger dataLogger, Foo object) {
|
||||
// public void update(EpilogueBackend backend, Foo object) {
|
||||
out.println(" @Override");
|
||||
out.println(" public void update(DataLogger dataLogger, " + simpleClassName + " object) {");
|
||||
out.println(
|
||||
" public void update(EpilogueBackend backend, " + simpleClassName + " object) {");
|
||||
|
||||
// Build a map of importance levels to the fields logged at those levels
|
||||
// e.g. { DEBUG: [fieldA, fieldB], INFO: [fieldC], CRITICAL: [fieldD, fieldE, fieldF] }
|
||||
|
||||
@@ -31,7 +31,7 @@ public class MeasureHandler extends ElementHandler {
|
||||
|
||||
@Override
|
||||
public String logInvocation(Element element) {
|
||||
// DataLogger has builtin support for logging measures
|
||||
return "dataLogger.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
// EpilogueBackend has builtin support for logging measures
|
||||
return "backend.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@ public class PrimitiveHandler extends ElementHandler {
|
||||
|
||||
@Override
|
||||
public String logInvocation(Element element) {
|
||||
return "dataLogger.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
return "backend.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,24 +4,32 @@
|
||||
|
||||
package edu.wpi.first.epilogue.processor;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
public class SendableHandler extends ElementHandler {
|
||||
private final TypeMirror m_sendableType;
|
||||
private final TypeMirror m_commandType;
|
||||
private final TypeMirror m_subsystemType;
|
||||
private final Optional<TypeMirror> m_sendableType;
|
||||
private final Optional<TypeMirror> m_commandType;
|
||||
private final Optional<TypeMirror> m_subsystemType;
|
||||
|
||||
protected SendableHandler(ProcessingEnvironment processingEnv) {
|
||||
super(processingEnv);
|
||||
|
||||
m_sendableType =
|
||||
lookupTypeElement(processingEnv, "edu.wpi.first.util.sendable.Sendable").asType();
|
||||
Optional.ofNullable(
|
||||
lookupTypeElement(processingEnv, "edu.wpi.first.util.sendable.Sendable"))
|
||||
.map(TypeElement::asType);
|
||||
m_commandType =
|
||||
lookupTypeElement(processingEnv, "edu.wpi.first.wpilibj2.command.Command").asType();
|
||||
Optional.ofNullable(
|
||||
lookupTypeElement(processingEnv, "edu.wpi.first.wpilibj2.command.Command"))
|
||||
.map(TypeElement::asType);
|
||||
m_subsystemType =
|
||||
lookupTypeElement(processingEnv, "edu.wpi.first.wpilibj2.command.SubsystemBase").asType();
|
||||
Optional.ofNullable(
|
||||
lookupTypeElement(processingEnv, "edu.wpi.first.wpilibj2.command.SubsystemBase"))
|
||||
.map(TypeElement::asType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -30,24 +38,32 @@ public class SendableHandler extends ElementHandler {
|
||||
|
||||
// Accept any sendable type. However, the log invocation will return null
|
||||
// for sendable types that should not be logged (commands, subsystems)
|
||||
return m_processingEnv.getTypeUtils().isAssignable(dataType, m_sendableType);
|
||||
return m_sendableType
|
||||
.map(t -> m_processingEnv.getTypeUtils().isAssignable(dataType, t))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String logInvocation(Element element) {
|
||||
var dataType = dataType(element);
|
||||
|
||||
if (m_processingEnv.getTypeUtils().isAssignable(dataType, m_commandType)
|
||||
|| m_processingEnv.getTypeUtils().isAssignable(dataType, m_subsystemType)) {
|
||||
// Do not log commands or subsystems via their sendable implementations
|
||||
// We accept all sendable objects to prevent them from being reported as not loggable,
|
||||
// but their sendable implementations do not include helpful information.
|
||||
// Users are free to provide custom logging implementations for commands, and tag their
|
||||
// subsystems with @Logged to log their contents automatically
|
||||
// Do not log commands or subsystems via their sendable implementations
|
||||
// We accept all sendable objects to prevent them from being reported as not loggable,
|
||||
// but their sendable implementations do not include helpful information.
|
||||
// Users are free to provide custom logging implementations for commands, and tag their
|
||||
// subsystems with @Logged to log their contents automatically
|
||||
if (m_commandType
|
||||
.map(t -> m_processingEnv.getTypeUtils().isAssignable(dataType, t))
|
||||
.orElse(false)) {
|
||||
return null;
|
||||
}
|
||||
if (m_subsystemType
|
||||
.map(t -> m_processingEnv.getTypeUtils().isAssignable(dataType, t))
|
||||
.orElse(false)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return "logSendable(dataLogger.getSubLogger(\""
|
||||
return "logSendable(backend.getNested(\""
|
||||
+ loggedName(element)
|
||||
+ "\"), "
|
||||
+ elementAccess(element)
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
package edu.wpi.first.epilogue.processor;
|
||||
|
||||
import edu.wpi.first.epilogue.Logged;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
public final class StringUtils {
|
||||
@@ -108,34 +112,24 @@ public final class StringUtils {
|
||||
*/
|
||||
public static String loggerClassName(TypeElement clazz) {
|
||||
var config = clazz.getAnnotation(Logged.class);
|
||||
var className = clazz.getQualifiedName().toString();
|
||||
|
||||
String packageName;
|
||||
int lastDot = className.lastIndexOf('.');
|
||||
if (lastDot <= 0) {
|
||||
packageName = null;
|
||||
Deque<String> nesting = new ArrayDeque<>();
|
||||
Element enclosing = clazz.getEnclosingElement();
|
||||
while (!(enclosing instanceof PackageElement p)) {
|
||||
nesting.addFirst(enclosing.getSimpleName().toString());
|
||||
enclosing = enclosing.getEnclosingElement();
|
||||
}
|
||||
nesting.addLast(clazz.getSimpleName().toString());
|
||||
String packageName = p.getQualifiedName().toString();
|
||||
|
||||
String className;
|
||||
if (config == null || config.name().isEmpty()) {
|
||||
className = String.join("$", nesting);
|
||||
} else {
|
||||
packageName = className.substring(0, lastDot);
|
||||
className = capitalize(config.name()).replaceAll(" ", "");
|
||||
}
|
||||
|
||||
String loggerClassName;
|
||||
|
||||
// Use the name on the class config to set the generated logger names
|
||||
// This helps to avoid naming conflicts
|
||||
if (config.name().isBlank()) {
|
||||
loggerClassName = className + "Logger";
|
||||
} else {
|
||||
String cleaned = config.name().replaceAll(" ", "");
|
||||
|
||||
var loggerSimpleClassName = StringUtils.capitalize(cleaned) + "Logger";
|
||||
if (packageName != null) {
|
||||
loggerClassName = packageName + "." + loggerSimpleClassName;
|
||||
} else {
|
||||
loggerClassName = loggerSimpleClassName;
|
||||
}
|
||||
}
|
||||
|
||||
return loggerClassName;
|
||||
return packageName + "." + className + "Logger";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,7 +39,7 @@ public class StructHandler extends ElementHandler {
|
||||
|
||||
@Override
|
||||
public String logInvocation(Element element) {
|
||||
return "dataLogger.log(\""
|
||||
return "backend.log(\""
|
||||
+ loggedName(element)
|
||||
+ "\", "
|
||||
+ elementAccess(element)
|
||||
|
||||
@@ -43,7 +43,7 @@ public class SupplierHandler extends ElementHandler {
|
||||
|
||||
@Override
|
||||
public String logInvocation(Element element) {
|
||||
return "dataLogger.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
return "backend.log(\"" + loggedName(element) + "\", " + elementAccess(element) + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,9 +33,19 @@ class EpilogueGeneratorTest {
|
||||
|
||||
import static edu.wpi.first.units.Units.Seconds;
|
||||
|
||||
import edu.wpi.first.hal.FRCNetComm;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
|
||||
import edu.wpi.first.epilogue.ExampleLogger;
|
||||
|
||||
public final class Epilogue {
|
||||
static {
|
||||
HAL.report(
|
||||
FRCNetComm.tResourceType.kResourceType_LoggingFramework,
|
||||
FRCNetComm.tInstances.kLoggingFramework_Epilogue
|
||||
);
|
||||
}
|
||||
|
||||
private static final EpilogueConfiguration config = new EpilogueConfiguration();
|
||||
|
||||
public static final ExampleLogger exampleLogger = new ExampleLogger();
|
||||
@@ -82,9 +92,19 @@ class EpilogueGeneratorTest {
|
||||
|
||||
import static edu.wpi.first.units.Units.Seconds;
|
||||
|
||||
import edu.wpi.first.hal.FRCNetComm;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
|
||||
import edu.wpi.first.epilogue.ExampleLogger;
|
||||
|
||||
public final class Epilogue {
|
||||
static {
|
||||
HAL.report(
|
||||
FRCNetComm.tResourceType.kResourceType_LoggingFramework,
|
||||
FRCNetComm.tInstances.kLoggingFramework_Epilogue
|
||||
);
|
||||
}
|
||||
|
||||
private static final EpilogueConfiguration config = new EpilogueConfiguration();
|
||||
|
||||
public static final ExampleLogger exampleLogger = new ExampleLogger();
|
||||
@@ -126,9 +146,19 @@ class EpilogueGeneratorTest {
|
||||
|
||||
import static edu.wpi.first.units.Units.Seconds;
|
||||
|
||||
import edu.wpi.first.hal.FRCNetComm;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
|
||||
import edu.wpi.first.epilogue.ExampleLogger;
|
||||
|
||||
public final class Epilogue {
|
||||
static {
|
||||
HAL.report(
|
||||
FRCNetComm.tResourceType.kResourceType_LoggingFramework,
|
||||
FRCNetComm.tInstances.kLoggingFramework_Epilogue
|
||||
);
|
||||
}
|
||||
|
||||
private static final EpilogueConfiguration config = new EpilogueConfiguration();
|
||||
|
||||
public static final ExampleLogger exampleLogger = new ExampleLogger();
|
||||
@@ -155,8 +185,8 @@ class EpilogueGeneratorTest {
|
||||
*/
|
||||
public static void update(edu.wpi.first.epilogue.Example robot) {
|
||||
long start = System.nanoTime();
|
||||
exampleLogger.tryUpdate(config.dataLogger.getSubLogger(config.root), robot, config.errorHandler);
|
||||
config.dataLogger.log(\"Epilogue/Stats/Last Run\", (System.nanoTime() - start) / 1e6);
|
||||
exampleLogger.tryUpdate(config.backend.getNested(config.root), robot, config.errorHandler);
|
||||
config.backend.log(\"Epilogue/Stats/Last Run\", (System.nanoTime() - start) / 1e6);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,10 +234,20 @@ class EpilogueGeneratorTest {
|
||||
|
||||
import static edu.wpi.first.units.Units.Seconds;
|
||||
|
||||
import edu.wpi.first.hal.FRCNetComm;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
|
||||
import edu.wpi.first.epilogue.AlphaBotLogger;
|
||||
import edu.wpi.first.epilogue.BetaBotLogger;
|
||||
|
||||
public final class Epilogue {
|
||||
static {
|
||||
HAL.report(
|
||||
FRCNetComm.tResourceType.kResourceType_LoggingFramework,
|
||||
FRCNetComm.tInstances.kLoggingFramework_Epilogue
|
||||
);
|
||||
}
|
||||
|
||||
private static final EpilogueConfiguration config = new EpilogueConfiguration();
|
||||
|
||||
public static final AlphaBotLogger alphaBotLogger = new AlphaBotLogger();
|
||||
@@ -235,8 +275,8 @@ class EpilogueGeneratorTest {
|
||||
*/
|
||||
public static void update(edu.wpi.first.epilogue.AlphaBot robot) {
|
||||
long start = System.nanoTime();
|
||||
alphaBotLogger.tryUpdate(config.dataLogger.getSubLogger(config.root), robot, config.errorHandler);
|
||||
config.dataLogger.log(\"Epilogue/Stats/Last Run\", (System.nanoTime() - start) / 1e6);
|
||||
alphaBotLogger.tryUpdate(config.backend.getNested(config.root), robot, config.errorHandler);
|
||||
config.backend.log(\"Epilogue/Stats/Last Run\", (System.nanoTime() - start) / 1e6);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,8 +307,8 @@ class EpilogueGeneratorTest {
|
||||
*/
|
||||
public static void update(edu.wpi.first.epilogue.BetaBot robot) {
|
||||
long start = System.nanoTime();
|
||||
betaBotLogger.tryUpdate(config.dataLogger.getSubLogger(config.root), robot, config.errorHandler);
|
||||
config.dataLogger.log(\"Epilogue/Stats/Last Run\", (System.nanoTime() - start) / 1e6);
|
||||
betaBotLogger.tryUpdate(config.backend.getNested(config.root), robot, config.errorHandler);
|
||||
config.backend.log(\"Epilogue/Stats/Last Run\", (System.nanoTime() - start) / 1e6);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,7 +354,7 @@ class EpilogueGeneratorTest {
|
||||
public CustomLogger() { super(A.class); }
|
||||
|
||||
@Override
|
||||
public void update(DataLogger logger, A object) {} // implementation is irrelevant
|
||||
public void update(EpilogueBackend backend, A object) {} // implementation is irrelevant
|
||||
}
|
||||
|
||||
@Logged
|
||||
@@ -331,10 +371,20 @@ class EpilogueGeneratorTest {
|
||||
|
||||
import static edu.wpi.first.units.Units.Seconds;
|
||||
|
||||
import edu.wpi.first.hal.FRCNetComm;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
|
||||
import edu.wpi.first.epilogue.ExampleLogger;
|
||||
import edu.wpi.first.epilogue.CustomLogger;
|
||||
|
||||
public final class Epilogue {
|
||||
static {
|
||||
HAL.report(
|
||||
FRCNetComm.tResourceType.kResourceType_LoggingFramework,
|
||||
FRCNetComm.tInstances.kLoggingFramework_Epilogue
|
||||
);
|
||||
}
|
||||
|
||||
private static final EpilogueConfiguration config = new EpilogueConfiguration();
|
||||
|
||||
public static final ExampleLogger exampleLogger = new ExampleLogger();
|
||||
|
||||
12
epilogue-runtime/BUILD.bazel
Normal file
12
epilogue-runtime/BUILD.bazel
Normal file
@@ -0,0 +1,12 @@
|
||||
load("@rules_java//java:defs.bzl", "java_library")
|
||||
|
||||
java_library(
|
||||
name = "epilogue",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//ntcore:networktables-java",
|
||||
"//wpiunits",
|
||||
"//wpiutil:wpiutil-java",
|
||||
],
|
||||
)
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
package edu.wpi.first.epilogue;
|
||||
|
||||
import edu.wpi.first.epilogue.logging.DataLogger;
|
||||
import edu.wpi.first.epilogue.logging.NTDataLogger;
|
||||
import edu.wpi.first.epilogue.logging.EpilogueBackend;
|
||||
import edu.wpi.first.epilogue.logging.NTEpilogueBackend;
|
||||
import edu.wpi.first.epilogue.logging.errors.ErrorHandler;
|
||||
import edu.wpi.first.epilogue.logging.errors.ErrorPrinter;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
@@ -18,11 +18,11 @@ import edu.wpi.first.units.measure.Time;
|
||||
@SuppressWarnings("checkstyle:MemberName")
|
||||
public class EpilogueConfiguration {
|
||||
/**
|
||||
* The data logger implementation for Epilogue to use. By default, this will log data directly to
|
||||
* The backend implementation for Epilogue to use. By default, this will log data directly to
|
||||
* NetworkTables. NetworkTable data can be mirrored to a log file on disk by calling {@code
|
||||
* DataLogManager.start()} in your {@code robotInit} method.
|
||||
*/
|
||||
public DataLogger dataLogger = new NTDataLogger(NetworkTableInstance.getDefault());
|
||||
public EpilogueBackend backend = new NTEpilogueBackend(NetworkTableInstance.getDefault());
|
||||
|
||||
/**
|
||||
* The period Epilogue will log at. By default this is the period that the robot runs at. This is
|
||||
|
||||
@@ -124,4 +124,12 @@ public @interface Logged {
|
||||
* for all logged fields and methods in an annotated class
|
||||
*/
|
||||
Naming defaultNaming() default Naming.USE_CODE_NAME;
|
||||
|
||||
/**
|
||||
* Class-level only: if {@link #strategy()} is {@link Strategy#OPT_OUT}, this can be used to quiet
|
||||
* the warnings that are printed for non-loggable fields and methods detected within the class.
|
||||
*
|
||||
* @return true if warnings should be printed, or false if warnings should not be printed
|
||||
*/
|
||||
boolean warnForNonLoggableTypes() default false;
|
||||
}
|
||||
|
||||
@@ -42,26 +42,26 @@ public abstract class ClassSpecificLogger<T> {
|
||||
/**
|
||||
* Updates an object's fields in a data log.
|
||||
*
|
||||
* @param dataLogger the logger to update
|
||||
* @param backend the backend to update
|
||||
* @param object the object to update in the log
|
||||
*/
|
||||
protected abstract void update(DataLogger dataLogger, T object);
|
||||
protected abstract void update(EpilogueBackend backend, T object);
|
||||
|
||||
/**
|
||||
* Attempts to update the data log. Will do nothing if the logger is {@link #disable() disabled}.
|
||||
*
|
||||
* @param dataLogger the logger to log data to
|
||||
* @param backend the backend to log data to
|
||||
* @param object the data object to log
|
||||
* @param errorHandler the handler to use if logging raised an exception
|
||||
*/
|
||||
@SuppressWarnings("PMD.AvoidCatchingGenericException")
|
||||
public final void tryUpdate(DataLogger dataLogger, T object, ErrorHandler errorHandler) {
|
||||
public final void tryUpdate(EpilogueBackend backend, T object, ErrorHandler errorHandler) {
|
||||
if (m_disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
update(dataLogger, object);
|
||||
update(backend, object);
|
||||
} catch (Exception e) {
|
||||
errorHandler.handle(e, this);
|
||||
}
|
||||
@@ -98,10 +98,10 @@ public abstract class ClassSpecificLogger<T> {
|
||||
/**
|
||||
* Logs a sendable type.
|
||||
*
|
||||
* @param dataLogger the logger to log data into
|
||||
* @param backend the backend to log data into
|
||||
* @param sendable the sendable object to log
|
||||
*/
|
||||
protected void logSendable(DataLogger dataLogger, Sendable sendable) {
|
||||
protected void logSendable(EpilogueBackend backend, Sendable sendable) {
|
||||
if (sendable == null) {
|
||||
return;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public abstract class ClassSpecificLogger<T> {
|
||||
m_sendables.computeIfAbsent(
|
||||
sendable,
|
||||
s -> {
|
||||
var b = new LogBackedSendableBuilder(dataLogger);
|
||||
var b = new LogBackedSendableBuilder(backend);
|
||||
s.initSendable(b);
|
||||
return b;
|
||||
});
|
||||
|
||||
@@ -9,40 +9,40 @@ import edu.wpi.first.units.Unit;
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
import java.util.Collection;
|
||||
|
||||
/** A data logger is a generic interface for logging discrete data points. */
|
||||
public interface DataLogger {
|
||||
/** A backend is a generic interface for Epilogue to log discrete data points. */
|
||||
public interface EpilogueBackend {
|
||||
/**
|
||||
* Creates a data logger that logs to multiple backends at once. Data reads will still only occur
|
||||
* once; data is passed to all composed loggers at once.
|
||||
* Creates a backend that logs to multiple backends at once. Data reads will still only occur
|
||||
* once; data is passed to all composed backends at once.
|
||||
*
|
||||
* @param loggers the loggers to compose together
|
||||
* @return the multi logger
|
||||
* @param backends the backends to compose together
|
||||
* @return the multi backend
|
||||
*/
|
||||
static DataLogger multi(DataLogger... loggers) {
|
||||
return new MultiLogger(loggers);
|
||||
static EpilogueBackend multi(EpilogueBackend... backends) {
|
||||
return new MultiBackend(backends);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a lazy version of this logger. A lazy logger will only log data to a field when its
|
||||
* Creates a lazy version of this backend. A lazy backend will only log data to a field when its
|
||||
* value changes, which can help keep file size and bandwidth usage in check. However, there is an
|
||||
* additional CPU and memory overhead associated with tracking the current value of every logged
|
||||
* entry. The most surefire way to reduce CPU and memory usage associated with logging is to log
|
||||
* fewer things - which can be done by opting out of logging unnecessary data or increasing the
|
||||
* minimum logged importance level in the Epilogue configuration.
|
||||
*
|
||||
* @return the lazy logger
|
||||
* @return the lazy backend
|
||||
*/
|
||||
default DataLogger lazy() {
|
||||
return new LazyLogger(this);
|
||||
default EpilogueBackend lazy() {
|
||||
return new LazyBackend(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a logger that can be used to log nested data underneath a specific path.
|
||||
* Gets a backend that can be used to log nested data underneath a specific path.
|
||||
*
|
||||
* @param path the path to use for logging nested data under
|
||||
* @return the sub logger
|
||||
* @return the nested backend
|
||||
*/
|
||||
DataLogger getSubLogger(String path);
|
||||
EpilogueBackend getNested(String path);
|
||||
|
||||
/**
|
||||
* Logs a 32-bit integer data point.
|
||||
@@ -26,24 +26,24 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/** A data logger implementation that saves information to a WPILib {@link DataLog} file on disk. */
|
||||
public class FileLogger implements DataLogger {
|
||||
/** A backend implementation that saves information to a WPILib {@link DataLog} file on disk. */
|
||||
public class FileBackend implements EpilogueBackend {
|
||||
private final DataLog m_dataLog;
|
||||
private final Map<String, DataLogEntry> m_entries = new HashMap<>();
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final Map<String, NestedBackend> m_subLoggers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new file logger.
|
||||
* Creates a new file-based backend.
|
||||
*
|
||||
* @param dataLog the data log to save data to
|
||||
*/
|
||||
public FileLogger(DataLog dataLog) {
|
||||
this.m_dataLog = requireNonNullParam(dataLog, "dataLog", "FileLogger");
|
||||
public FileBackend(DataLog dataLog) {
|
||||
this.m_dataLog = requireNonNullParam(dataLog, "dataLog", "FileBackend");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -11,36 +11,36 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A data logger implementation that only logs data when it changes. Useful for keeping bandwidth
|
||||
* and file sizes down. However, because it still needs to check that data has changed, it cannot
|
||||
* avoid expensive sensor reads.
|
||||
* A backend implementation that only logs data when it changes. Useful for keeping bandwidth and
|
||||
* file sizes down. However, because it still needs to check that data has changed, it cannot avoid
|
||||
* expensive sensor reads.
|
||||
*/
|
||||
public class LazyLogger implements DataLogger {
|
||||
private final DataLogger m_logger;
|
||||
public class LazyBackend implements EpilogueBackend {
|
||||
private final EpilogueBackend m_backend;
|
||||
|
||||
// Keep a record of the most recent value written to each entry
|
||||
// Note that this may duplicate a lot of data, and will box primitives.
|
||||
private final Map<String, Object> m_previousValues = new HashMap<>();
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final Map<String, NestedBackend> m_subLoggers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new lazy logger wrapper around another logger.
|
||||
* Creates a new lazy backend wrapper around another backend.
|
||||
*
|
||||
* @param logger the logger to delegate to
|
||||
* @param backend the backend to delegate to
|
||||
*/
|
||||
public LazyLogger(DataLogger logger) {
|
||||
this.m_logger = logger;
|
||||
public LazyBackend(EpilogueBackend backend) {
|
||||
this.m_backend = backend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger lazy() {
|
||||
public EpilogueBackend lazy() {
|
||||
// Already lazy, don't need to wrap it again
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,7 +53,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +66,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +79,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,7 +92,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,7 +105,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,8 +117,8 @@ public class LazyLogger implements DataLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_previousValues.put(identifier, value.clone());
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,8 +130,8 @@ public class LazyLogger implements DataLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_previousValues.put(identifier, value.clone());
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,8 +143,8 @@ public class LazyLogger implements DataLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_previousValues.put(identifier, value.clone());
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -156,8 +156,8 @@ public class LazyLogger implements DataLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_previousValues.put(identifier, value.clone());
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,8 +169,8 @@ public class LazyLogger implements DataLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_previousValues.put(identifier, value.clone());
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -182,8 +182,8 @@ public class LazyLogger implements DataLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_previousValues.put(identifier, value.clone());
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -196,7 +196,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -208,8 +208,8 @@ public class LazyLogger implements DataLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_previousValues.put(identifier, value.clone());
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,7 +222,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value, struct);
|
||||
m_backend.log(identifier, value, struct);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -234,7 +234,7 @@ public class LazyLogger implements DataLogger {
|
||||
return;
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value, struct);
|
||||
m_previousValues.put(identifier, value.clone());
|
||||
m_backend.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
@@ -18,24 +18,24 @@ import java.util.function.LongConsumer;
|
||||
import java.util.function.LongSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/** A sendable builder implementation that sends data to a {@link DataLogger}. */
|
||||
@SuppressWarnings("PMD.CouplingBetweenObjects") // most methods simply delegate to the logger
|
||||
/** A sendable builder implementation that sends data to a {@link EpilogueBackend}. */
|
||||
@SuppressWarnings("PMD.CouplingBetweenObjects") // most methods simply delegate to the backend
|
||||
public class LogBackedSendableBuilder implements SendableBuilder {
|
||||
private final DataLogger m_logger;
|
||||
private final EpilogueBackend m_backend;
|
||||
private final Collection<Runnable> m_updates = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new sendable builder that delegates writes to an underlying data logger.
|
||||
* Creates a new sendable builder that delegates writes to an underlying backend.
|
||||
*
|
||||
* @param logger the data logger to write the sendable data to
|
||||
* @param backend the backend to write the sendable data to
|
||||
*/
|
||||
public LogBackedSendableBuilder(DataLogger logger) {
|
||||
this.m_logger = logger;
|
||||
public LogBackedSendableBuilder(EpilogueBackend backend) {
|
||||
this.m_backend = backend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSmartDashboardType(String type) {
|
||||
m_logger.log(".type", type);
|
||||
m_backend.log(".type", type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,132 +50,132 @@ public class LogBackedSendableBuilder implements SendableBuilder {
|
||||
|
||||
@Override
|
||||
public void addBooleanProperty(String key, BooleanSupplier getter, BooleanConsumer setter) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.getAsBoolean()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.getAsBoolean()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstBoolean(String key, boolean value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIntegerProperty(String key, LongSupplier getter, LongConsumer setter) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.getAsLong()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.getAsLong()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstInteger(String key, long value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFloatProperty(String key, FloatSupplier getter, FloatConsumer setter) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.getAsFloat()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.getAsFloat()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstFloat(String key, float value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDoubleProperty(String key, DoubleSupplier getter, DoubleConsumer setter) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.getAsDouble()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.getAsDouble()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstDouble(String key, double value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStringProperty(String key, Supplier<String> getter, Consumer<String> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstString(String key, String value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBooleanArrayProperty(
|
||||
String key, Supplier<boolean[]> getter, Consumer<boolean[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstBooleanArray(String key, boolean[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIntegerArrayProperty(
|
||||
String key, Supplier<long[]> getter, Consumer<long[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstIntegerArray(String key, long[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFloatArrayProperty(
|
||||
String key, Supplier<float[]> getter, Consumer<float[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstFloatArray(String key, float[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDoubleArrayProperty(
|
||||
String key, Supplier<double[]> getter, Consumer<double[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstDoubleArray(String key, double[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStringArrayProperty(
|
||||
String key, Supplier<String[]> getter, Consumer<String[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstStringArray(String key, String[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRawProperty(
|
||||
String key, String typeString, Supplier<byte[]> getter, Consumer<byte[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstRaw(String key, String typeString, byte[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A backend implementation that delegates to other backends. Helpful for simultaneous logging to
|
||||
* multiple data stores at once.
|
||||
*/
|
||||
public class MultiBackend implements EpilogueBackend {
|
||||
private final List<EpilogueBackend> m_backends;
|
||||
private final Map<String, NestedBackend> m_nestedBackends = new HashMap<>();
|
||||
|
||||
// Use EpilogueBackend.multi(...) instead of instantiation directly
|
||||
MultiBackend(EpilogueBackend... backends) {
|
||||
this.m_backends = List.of(backends);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_nestedBackends.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, byte[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S value, Struct<S> struct) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S[] value, Struct<S> struct) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A data logger implementation that delegates to other loggers. Helpful for simultaneous logging to
|
||||
* multiple data stores at once.
|
||||
*/
|
||||
public class MultiLogger implements DataLogger {
|
||||
private final List<DataLogger> m_loggers;
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
|
||||
// Use DataLogger.multi(...) instead of instantiation directly
|
||||
MultiLogger(DataLogger... loggers) {
|
||||
this.m_loggers = List.of(loggers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, byte[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S value, Struct<S> struct) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S[] value, Struct<S> struct) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,27 +24,27 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A data logger implementation that sends data over network tables. Be careful when using this,
|
||||
* since sending too much data may cause bandwidth or CPU starvation.
|
||||
* A backend implementation that sends data over network tables. Be careful when using this, since
|
||||
* sending too much data may cause bandwidth or CPU starvation.
|
||||
*/
|
||||
public class NTDataLogger implements DataLogger {
|
||||
public class NTEpilogueBackend implements EpilogueBackend {
|
||||
private final NetworkTableInstance m_nt;
|
||||
|
||||
private final Map<String, Publisher> m_publishers = new HashMap<>();
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final Map<String, NestedBackend> m_nestedBackends = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a data logger that sends information to NetworkTables.
|
||||
* Creates a logging backend that sends information to NetworkTables.
|
||||
*
|
||||
* @param nt the NetworkTable instance to use to send data to
|
||||
*/
|
||||
public NTDataLogger(NetworkTableInstance nt) {
|
||||
public NTEpilogueBackend(NetworkTableInstance nt) {
|
||||
this.m_nt = nt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_nestedBackends.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -9,21 +9,21 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A data logger that logs to an underlying logger, prepending all logged data with a specific
|
||||
* prefix. Useful for logging nested data structures.
|
||||
* A backend that logs to an underlying backend, prepending all logged data with a specific prefix.
|
||||
* Useful for logging nested data structures.
|
||||
*/
|
||||
public class SubLogger implements DataLogger {
|
||||
public class NestedBackend implements EpilogueBackend {
|
||||
private final String m_prefix;
|
||||
private final DataLogger m_impl;
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final EpilogueBackend m_impl;
|
||||
private final Map<String, NestedBackend> m_nestedBackends = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new sublogger underneath another logger.
|
||||
* Creates a new nested backed underneath another backend.
|
||||
*
|
||||
* @param prefix the prefix to append to all data logged in the sublogger
|
||||
* @param impl the data logger to log to
|
||||
* @param prefix the prefix to append to all data logged in the nested backend
|
||||
* @param impl the backend to log to
|
||||
*/
|
||||
public SubLogger(String prefix, DataLogger impl) {
|
||||
public NestedBackend(String prefix, EpilogueBackend impl) {
|
||||
// Add a trailing slash if not already present
|
||||
if (prefix.endsWith("/")) {
|
||||
this.m_prefix = prefix;
|
||||
@@ -34,8 +34,8 @@ public class SubLogger implements DataLogger {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_nestedBackends.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -6,14 +6,14 @@ package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
|
||||
/** Null data logger implementation that logs nothing. */
|
||||
public class NullLogger implements DataLogger {
|
||||
/** Null backend implementation that logs nothing. */
|
||||
public class NullBackend implements EpilogueBackend {
|
||||
/** Default constructor. */
|
||||
public NullLogger() {}
|
||||
public NullBackend() {}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
// Since a sublogger would still log nothing and has no state, we can just return the same
|
||||
public EpilogueBackend getNested(String path) {
|
||||
// Since a nested backend would still log nothing and has no state, we can just return the same
|
||||
// null-logging implementation
|
||||
return this;
|
||||
}
|
||||
@@ -19,10 +19,10 @@ class ClassSpecificLoggerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update(DataLogger dataLogger, Point2d object) {
|
||||
dataLogger.log("x", object.x);
|
||||
dataLogger.log("y", object.y);
|
||||
dataLogger.log("dim", object.dim);
|
||||
protected void update(EpilogueBackend backend, Point2d object) {
|
||||
backend.log("x", object.x);
|
||||
backend.log("y", object.y);
|
||||
backend.log("dim", object.dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,14 +31,14 @@ class ClassSpecificLoggerTest {
|
||||
void testReadPrivate() {
|
||||
var point = new Point2d(1, 4, 2);
|
||||
var logger = new Point2d.Logger();
|
||||
var dataLog = new TestLogger();
|
||||
logger.update(dataLog.getSubLogger("Point"), point);
|
||||
var dataLog = new TestBackend();
|
||||
logger.update(dataLog.getNested("Point"), point);
|
||||
|
||||
assertEquals(
|
||||
List.of(
|
||||
new TestLogger.LogEntry<>("Point/x", 1.0),
|
||||
new TestLogger.LogEntry<>("Point/y", 4.0),
|
||||
new TestLogger.LogEntry<>("Point/dim", 2)),
|
||||
new TestBackend.LogEntry<>("Point/x", 1.0),
|
||||
new TestBackend.LogEntry<>("Point/y", 4.0),
|
||||
new TestBackend.LogEntry<>("Point/dim", 2)),
|
||||
dataLog.getEntries());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
import edu.wpi.first.util.struct.StructSerializable;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public record CustomStruct(int x) implements StructSerializable {
|
||||
public static final Serializer struct = new Serializer();
|
||||
|
||||
public static final class Serializer implements Struct<CustomStruct> {
|
||||
@Override
|
||||
public Class<CustomStruct> getTypeClass() {
|
||||
return CustomStruct.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "CustomStruct";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return kSizeInt32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSchema() {
|
||||
return "int32 x;";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomStruct unpack(ByteBuffer bb) {
|
||||
return new CustomStruct(bb.getInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pack(ByteBuffer bb, CustomStruct value) {
|
||||
bb.putInt(value.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LazyBackendTest {
|
||||
@Test
|
||||
void lazyOfLazyReturnsSelf() {
|
||||
var lazy = new LazyBackend(new NullBackend());
|
||||
assertSame(lazy, lazy.lazy());
|
||||
}
|
||||
|
||||
@Test
|
||||
void lazyInt() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
{
|
||||
// First time logging to "int" should go through
|
||||
lazy.log("int", 0);
|
||||
assertEquals(List.of(new TestBackend.LogEntry<>("int", 0)), backend.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
// Logging the current value shouldn't go through
|
||||
lazy.log("int", 0);
|
||||
assertEquals(List.of(new TestBackend.LogEntry<>("int", 0)), backend.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
// Logging a new value should go through
|
||||
lazy.log("int", 1);
|
||||
assertEquals(
|
||||
List.of(new TestBackend.LogEntry<>("int", 0), new TestBackend.LogEntry<>("int", 1)),
|
||||
backend.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
// Logging a previous value should go through
|
||||
lazy.log("int", 0);
|
||||
assertEquals(
|
||||
List.of(
|
||||
new TestBackend.LogEntry<>("int", 0),
|
||||
new TestBackend.LogEntry<>("int", 1),
|
||||
new TestBackend.LogEntry<>("int", 0)),
|
||||
backend.getEntries());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void inPlaceByteArray() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
byte[] arr = new byte[] {0};
|
||||
lazy.log("arr", arr);
|
||||
|
||||
arr[0] = 1;
|
||||
lazy.log("arr", arr);
|
||||
|
||||
assertEquals(2, backend.getEntries().size());
|
||||
assertArrayEquals(new byte[] {0}, (byte[]) backend.getEntries().get(0).value());
|
||||
assertArrayEquals(new byte[] {1}, (byte[]) backend.getEntries().get(1).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void inPlaceIntArray() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
int[] arr = new int[] {0};
|
||||
lazy.log("arr", arr);
|
||||
|
||||
arr[0] = 1;
|
||||
lazy.log("arr", arr);
|
||||
|
||||
assertEquals(2, backend.getEntries().size());
|
||||
assertArrayEquals(new int[] {0}, (int[]) backend.getEntries().get(0).value());
|
||||
assertArrayEquals(new int[] {1}, (int[]) backend.getEntries().get(1).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void inPlaceLongArray() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
long[] arr = new long[] {0};
|
||||
lazy.log("arr", arr);
|
||||
|
||||
arr[0] = 1;
|
||||
lazy.log("arr", arr);
|
||||
|
||||
assertEquals(2, backend.getEntries().size());
|
||||
assertArrayEquals(new long[] {0}, (long[]) backend.getEntries().get(0).value());
|
||||
assertArrayEquals(new long[] {1}, (long[]) backend.getEntries().get(1).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void inPlaceFloatArray() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
float[] arr = new float[] {0};
|
||||
lazy.log("arr", arr);
|
||||
|
||||
arr[0] = 1;
|
||||
lazy.log("arr", arr);
|
||||
|
||||
assertEquals(2, backend.getEntries().size());
|
||||
assertArrayEquals(new float[] {0}, (float[]) backend.getEntries().get(0).value());
|
||||
assertArrayEquals(new float[] {1}, (float[]) backend.getEntries().get(1).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void inPlaceDoubleArray() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
double[] arr = new double[] {0};
|
||||
lazy.log("arr", arr);
|
||||
|
||||
arr[0] = 1;
|
||||
lazy.log("arr", arr);
|
||||
|
||||
assertEquals(2, backend.getEntries().size());
|
||||
assertArrayEquals(new double[] {0}, (double[]) backend.getEntries().get(0).value());
|
||||
assertArrayEquals(new double[] {1}, (double[]) backend.getEntries().get(1).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void inPlaceBooleanArray() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
boolean[] arr = new boolean[] {false};
|
||||
lazy.log("arr", arr);
|
||||
|
||||
arr[0] = true;
|
||||
lazy.log("arr", arr);
|
||||
|
||||
assertEquals(2, backend.getEntries().size());
|
||||
assertArrayEquals(new boolean[] {false}, (boolean[]) backend.getEntries().get(0).value());
|
||||
assertArrayEquals(new boolean[] {true}, (boolean[]) backend.getEntries().get(1).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void inPlaceStringArray() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
String[] arr = new String[] {"0"};
|
||||
lazy.log("arr", arr);
|
||||
|
||||
arr[0] = "1";
|
||||
lazy.log("arr", arr);
|
||||
|
||||
assertEquals(2, backend.getEntries().size());
|
||||
assertArrayEquals(new String[] {"0"}, (String[]) backend.getEntries().get(0).value());
|
||||
assertArrayEquals(new String[] {"1"}, (String[]) backend.getEntries().get(1).value());
|
||||
}
|
||||
|
||||
@Test
|
||||
void inPlaceStructArray() {
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
CustomStruct[] arr = new CustomStruct[] {new CustomStruct(0)};
|
||||
|
||||
lazy.log("arr", arr, CustomStruct.struct);
|
||||
|
||||
arr[0] = new CustomStruct(1);
|
||||
lazy.log("arr", arr, CustomStruct.struct);
|
||||
|
||||
assertEquals(2, backend.getEntries().size());
|
||||
assertArrayEquals(
|
||||
new byte[] {0x00, 0x00, 0x00, 0x00}, (byte[]) backend.getEntries().get(0).value());
|
||||
assertArrayEquals(
|
||||
new byte[] {0x01, 0x00, 0x00, 0x00}, (byte[]) backend.getEntries().get(1).value());
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LazyLoggerTest {
|
||||
@Test
|
||||
void lazyOfLazyReturnsSelf() {
|
||||
var lazy = new LazyLogger(new NullLogger());
|
||||
assertSame(lazy, lazy.lazy());
|
||||
}
|
||||
|
||||
@Test
|
||||
void lazyInt() {
|
||||
var logger = new TestLogger();
|
||||
var lazy = new LazyLogger(logger);
|
||||
|
||||
{
|
||||
// First time logging to "int" should go through
|
||||
lazy.log("int", 0);
|
||||
assertEquals(List.of(new TestLogger.LogEntry<>("int", 0)), logger.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
// Logging the current value shouldn't go through
|
||||
lazy.log("int", 0);
|
||||
assertEquals(List.of(new TestLogger.LogEntry<>("int", 0)), logger.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
// Logging a new value should go through
|
||||
lazy.log("int", 1);
|
||||
assertEquals(
|
||||
List.of(new TestLogger.LogEntry<>("int", 0), new TestLogger.LogEntry<>("int", 1)),
|
||||
logger.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
// Logging a previous value should go through
|
||||
lazy.log("int", 0);
|
||||
assertEquals(
|
||||
List.of(
|
||||
new TestLogger.LogEntry<>("int", 0),
|
||||
new TestLogger.LogEntry<>("int", 1),
|
||||
new TestLogger.LogEntry<>("int", 0)),
|
||||
logger.getEntries());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("PMD.TestClassWithoutTestCases") // This is not a test class!
|
||||
public class TestLogger implements DataLogger {
|
||||
public class TestBackend implements EpilogueBackend {
|
||||
public record LogEntry<T>(String identifier, T value) {}
|
||||
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final Map<String, NestedBackend> m_nestedBackends = new HashMap<>();
|
||||
|
||||
private final List<LogEntry<?>> m_entries = new ArrayList<>();
|
||||
|
||||
@@ -24,8 +24,8 @@ public class TestLogger implements DataLogger {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_nestedBackends.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,32 +55,32 @@ public class TestLogger implements DataLogger {
|
||||
|
||||
@Override
|
||||
public void log(String identifier, byte[] value) {
|
||||
m_entries.add(new LogEntry<>(identifier, value));
|
||||
m_entries.add(new LogEntry<>(identifier, value.clone()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int[] value) {
|
||||
m_entries.add(new LogEntry<>(identifier, value));
|
||||
m_entries.add(new LogEntry<>(identifier, value.clone()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long[] value) {
|
||||
m_entries.add(new LogEntry<>(identifier, value));
|
||||
m_entries.add(new LogEntry<>(identifier, value.clone()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float[] value) {
|
||||
m_entries.add(new LogEntry<>(identifier, value));
|
||||
m_entries.add(new LogEntry<>(identifier, value.clone()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double[] value) {
|
||||
m_entries.add(new LogEntry<>(identifier, value));
|
||||
m_entries.add(new LogEntry<>(identifier, value.clone()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean[] value) {
|
||||
m_entries.add(new LogEntry<>(identifier, value));
|
||||
m_entries.add(new LogEntry<>(identifier, value.clone()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,19 +90,27 @@ public class TestLogger implements DataLogger {
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String[] value) {
|
||||
m_entries.add(new LogEntry<>(identifier, value));
|
||||
m_entries.add(new LogEntry<>(identifier, value.clone()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S value, Struct<S> struct) {
|
||||
var serialized = StructBuffer.create(struct).write(value).array();
|
||||
var buffer = StructBuffer.create(struct).write(value).position(0);
|
||||
var serialized = new byte[buffer.capacity()];
|
||||
for (int i = 0; i < buffer.capacity(); i++) {
|
||||
serialized[i] = buffer.get();
|
||||
}
|
||||
|
||||
m_entries.add(new LogEntry<>(identifier, serialized));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S[] value, Struct<S> struct) {
|
||||
var serialized = StructBuffer.create(struct).writeArray(value).array();
|
||||
var buffer = StructBuffer.create(struct).writeArray(value).position(0);
|
||||
var serialized = new byte[buffer.capacity()];
|
||||
for (int i = 0; i < buffer.capacity(); i++) {
|
||||
serialized[i] = buffer.get();
|
||||
}
|
||||
|
||||
m_entries.add(new LogEntry<>(identifier, serialized));
|
||||
}
|
||||
31
fieldImages/BUILD.bazel
Normal file
31
fieldImages/BUILD.bazel
Normal file
@@ -0,0 +1,31 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
load("@rules_java//java:defs.bzl", "java_library")
|
||||
load("//shared/bazel/rules/gen:gen-resources.bzl", "generate_resources")
|
||||
|
||||
generate_resources(
|
||||
name = "generate-resources",
|
||||
namespace = "fields",
|
||||
prefix = "FIELDS",
|
||||
resource_files = glob(["src/main/native/resources/**"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "fieldImages",
|
||||
srcs = [":generate-resources"] + glob(["src/main/native/cpp/**"]),
|
||||
hdrs = glob(["src/main/native/include/**/*"]),
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "fieldImages-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
resource_strip_prefix = "fieldImages/src/main/native/resources",
|
||||
resources = glob(["src/main/native/resources/**"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"@maven//:com_fasterxml_jackson_core_jackson_annotations",
|
||||
"@maven//:com_fasterxml_jackson_core_jackson_databind",
|
||||
],
|
||||
)
|
||||
@@ -36,13 +36,13 @@ endif()
|
||||
|
||||
generate_resources(
|
||||
src/main/native/resources/edu/wpi/first/fields
|
||||
generated/main/cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/generated/main/cpp
|
||||
FIELDS
|
||||
fields
|
||||
field_images_resources_src
|
||||
)
|
||||
|
||||
add_library(fieldImages src/main/native/cpp/fields.cpp ${field_images_resources_src})
|
||||
add_library(fieldImages ${field_images_resources_src} src/main/native/cpp/fields.cpp)
|
||||
set_target_properties(fieldImages PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
set_property(TARGET fieldImages PROPERTY FOLDER "libraries")
|
||||
|
||||
@@ -16,12 +16,13 @@ public enum Fields {
|
||||
k2021Slalom("2021-slalompath.json"),
|
||||
k2022RapidReact("2022-rapidreact.json"),
|
||||
k2023ChargedUp("2023-chargedup.json"),
|
||||
k2024Crescendo("2024-crescendo.json");
|
||||
k2024Crescendo("2024-crescendo.json"),
|
||||
k2025Reefscape("2025-reefscape.json");
|
||||
|
||||
public static final String kBaseResourceDir = "/edu/wpi/first/fields/";
|
||||
|
||||
/** Alias to the current game. */
|
||||
public static final Fields kDefaultField = k2024Crescendo;
|
||||
public static final Fields kDefaultField = k2025Reefscape;
|
||||
|
||||
public final String m_resourceFile;
|
||||
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
#include "fields/2022-rapidreact.h"
|
||||
#include "fields/2023-chargedup.h"
|
||||
#include "fields/2024-crescendo.h"
|
||||
#include "fields/2025-reefscape.h"
|
||||
|
||||
using namespace fields;
|
||||
|
||||
static const Field kFields[] = {
|
||||
{"2025 Reefscape", GetResource_2025_reefscape_json,
|
||||
GetResource_2025_field_png},
|
||||
{"2024 Crescendo", GetResource_2024_crescendo_json,
|
||||
GetResource_2024_field_png},
|
||||
{"2023 Charged Up", GetResource_2023_chargedup_json,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user