mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
Merge branch 'main' into 2027
This commit is contained in:
61
.github/actions/pregen/action.yml
vendored
Normal file
61
.github/actions/pregen/action.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
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 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
|
||||
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 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
|
||||
103
.github/workflows/comment-command.yml
vendored
103
.github/workflows/comment-command.yml
vendored
@@ -1,103 +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-24.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: |
|
||||
python -m venv ${{ runner.temp }}/wpiformat
|
||||
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2024.50
|
||||
- name: Run wpiformat
|
||||
run: ${{ runner.temp }}/wpiformat/bin/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-24.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
|
||||
85
.github/workflows/pregen_all.py
vendored
85
.github/workflows/pregen_all.py
vendored
@@ -1,85 +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}/hal/generate_nanopb.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
|
||||
|
||||
27
WORKSPACE
27
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 = "fe267e2af53c1def1e962700a9aeda9e8fdfa9fb46b72167c615ec0e25447dd6",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodRio_toolchains/releases/download/2025-1/rules_bzlmodRio_toolchains-2025-1.tar.gz",
|
||||
)
|
||||
|
||||
load("@rules_bzlmodrio_toolchains//:maven_deps.bzl", "setup_legacy_setup_toolchains_dependencies")
|
||||
@@ -71,6 +71,12 @@ register_toolchains(
|
||||
"@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()
|
||||
@@ -87,8 +93,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 = "4f4a607956ca8555618736c3058dd96e09d02df19e95088c1e352d2319fd70c7",
|
||||
url = "https://github.com/wpilibsuite/bzlmodRio-opencv/releases/download/2025.4.10.0-2/bzlmodRio-opencv-2025.4.10.0-2.tar.gz",
|
||||
)
|
||||
|
||||
load("@bzlmodrio-opencv//:maven_cpp_deps.bzl", "setup_legacy_bzlmodrio_opencv_cpp_dependencies")
|
||||
@@ -98,3 +104,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"],
|
||||
)
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -133,6 +133,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('deploydeveloperRobotJavasystemcore')
|
||||
|
||||
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",
|
||||
],
|
||||
)
|
||||
@@ -43,6 +43,8 @@ public class LoggerGenerator {
|
||||
LoggerGenerator::isBuiltInJavaMethod;
|
||||
private final ProcessingEnvironment m_processingEnv;
|
||||
private final List<ElementHandler> m_handlers;
|
||||
|
||||
@SuppressWarnings("BadAnnotationImplementation")
|
||||
private final Logged m_defaultConfig =
|
||||
new Logged() {
|
||||
@Override
|
||||
|
||||
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",
|
||||
],
|
||||
)
|
||||
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",
|
||||
],
|
||||
)
|
||||
@@ -124,3 +124,4 @@ kResourceType_Koors40 = 122
|
||||
kResourceType_ThriftyNova = 123
|
||||
kResourceType_PWFSEN36005 = 124
|
||||
kResourceType_LaserShark = 125
|
||||
kResourceType_RevServoHub = 126
|
||||
|
||||
@@ -271,6 +271,8 @@ public final class FRCNetComm {
|
||||
public static final int kResourceType_PWFSEN36005 = 124;
|
||||
/** kResourceType_LaserShark = 125. */
|
||||
public static final int kResourceType_LaserShark = 125;
|
||||
/** kResourceType_RevServoHub = 126. */
|
||||
public static final int kResourceType_RevServoHub = 126;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -177,6 +177,7 @@ namespace HALUsageReporting {
|
||||
kResourceType_ThriftyNova = 123,
|
||||
kResourceType_PWFSEN36005 = 124,
|
||||
kResourceType_LaserShark = 125,
|
||||
kResourceType_RevServoHub = 126,
|
||||
};
|
||||
enum tInstances : int32_t {
|
||||
kLanguage_LabVIEW = 1,
|
||||
|
||||
@@ -146,6 +146,7 @@ typedef enum
|
||||
kResourceType_ThriftyNova = 123,
|
||||
kResourceType_PWFSEN36005 = 124,
|
||||
kResourceType_LaserShark = 125,
|
||||
kResourceType_RevServoHub = 126,
|
||||
|
||||
// kResourceType_MaximumID = 255,
|
||||
} tResourceType;
|
||||
|
||||
@@ -47,6 +47,8 @@ public final class CANAPITypes {
|
||||
kMiscellaneous(10),
|
||||
/** IO breakout. */
|
||||
kIOBreakout(11),
|
||||
/** Servo Controller. */
|
||||
kServoController(12),
|
||||
/** Firmware update. */
|
||||
kFirmwareUpdate(31);
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ HAL_ENUM(HAL_CANDeviceType) {
|
||||
HAL_CAN_Dev_kMiscellaneous = 10,
|
||||
/// IO breakout.
|
||||
HAL_CAN_Dev_kIOBreakout = 11,
|
||||
// Servo controller.
|
||||
HAL_CAN_Dev_kServoController = 12,
|
||||
/// Firmware update.
|
||||
HAL_CAN_Dev_kFirmwareUpdate = 31
|
||||
};
|
||||
|
||||
53
romiVendordep/BUILD.bazel
Normal file
53
romiVendordep/BUILD.bazel
Normal file
@@ -0,0 +1,53 @@
|
||||
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 = "romi-cpp.static",
|
||||
srcs = glob([
|
||||
"src/main/native/cpp/**",
|
||||
]),
|
||||
hdrs = glob(["src/main/native/include/**"]),
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//wpilibc:wpilibc.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "romi-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//hal:hal-java",
|
||||
"//wpilibj",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "romi-test",
|
||||
size = "small",
|
||||
srcs = glob(["src/test/native/cpp/**"]),
|
||||
deps = [
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
":romi-cpp.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "DevMain-Java",
|
||||
srcs = ["src/dev/java/edu/wpi/first/wpilibj/romi/DevMain.java"],
|
||||
main_class = "edu.wpi.first.wpilibj.romi.DevMain",
|
||||
deps = [
|
||||
"//hal:hal-java",
|
||||
"//ntcore:networktables-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
],
|
||||
)
|
||||
@@ -42,3 +42,6 @@ build:macos --linkopt=-Wl,-rpath,'@loader_path'"
|
||||
|
||||
# Things not in nativetools
|
||||
build:macos --copt=-Wno-shorten-64-to-32
|
||||
|
||||
build:macos --host_per_file_copt=external/zlib/.*\.c@-Wno-deprecated-non-prototype
|
||||
build:macos --host_per_file_copt=external/com_google_protobuf/.*\.cc@-Wno-unused-function
|
||||
|
||||
@@ -14,3 +14,5 @@ build:roborio --cxxopt=-Wno-error=deprecated-declarations
|
||||
|
||||
# Extra 11
|
||||
build:roborio --cxxopt=-Wno-error=deprecated-enum-enum-conversion
|
||||
|
||||
build:roborio --host_per_file_copt=external/zlib/.*\.c@-Wno-deprecated-non-prototype
|
||||
|
||||
@@ -67,8 +67,9 @@ def tagList = [
|
||||
"SmartDashboard", "Shuffleboard", "Sendable", "DataLog",
|
||||
|
||||
/* --- Controls --- */
|
||||
"Exponential Profile", "PID", "State-Space", "Path Following", "Trajectory", "SysId",
|
||||
"Simulation", "Trapezoid Profile", "Profiled PID", "Odometry", "LQR", "Pose Estimator",
|
||||
"Exponential Profile", "PID", "State-Space", "LTVUnicycleController", "Path Following",
|
||||
"Trajectory", "SysId", "Simulation", "Trapezoid Profile", "Profiled PID", "Odometry",
|
||||
"LQR", "Pose Estimator",
|
||||
|
||||
/* --- Hardware --- */
|
||||
"Analog", "Ultrasonic", "Gyro", "Pneumatics", "I2C", "Duty Cycle", "PDP", "DMA", "Relay",
|
||||
|
||||
87
wpilibNewCommands/BUILD.bazel
Normal file
87
wpilibNewCommands/BUILD.bazel
Normal file
@@ -0,0 +1,87 @@
|
||||
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 = "generated_cc_headers",
|
||||
hdrs = glob(["src/generated/main/native/include/**"]),
|
||||
includes = ["src/generated/main/native/include"],
|
||||
strip_include_prefix = "src/generated/main/native/include",
|
||||
visibility = ["//wpilibNewCommands:__subpackages__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "generated_cc_source",
|
||||
srcs = glob(["src/generated/main/native/cpp/**"]),
|
||||
visibility = ["//wpilibNewCommands:__subpackages__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "generated_java",
|
||||
srcs = glob(["src/generated/main/java/**/*.java"]),
|
||||
visibility = ["//wpilibNewCommands:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "wpilibNewCommands.static",
|
||||
srcs = glob(["src/main/native/cpp/**"]) + [":generated_cc_source"],
|
||||
hdrs = glob(["src/main/native/include/**"]),
|
||||
includes = ["src/main/native/include"],
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":generated_cc_headers",
|
||||
"//wpilibc:wpilibc.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "wpilibNewCommands-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]) + [":generated_java"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cscore:cscore-java",
|
||||
"//hal:hal-java",
|
||||
"//ntcore:networktables-java",
|
||||
"//wpilibj",
|
||||
"//wpimath:wpimath-java",
|
||||
"//wpinet:wpinet-java",
|
||||
"//wpiunits",
|
||||
"//wpiutil:wpiutil-java",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "wpilibNewCommands-cpp-test",
|
||||
size = "small",
|
||||
srcs = glob([
|
||||
"src/test/native/**/*.cpp",
|
||||
"src/test/native/**/*.h",
|
||||
]),
|
||||
tags = [
|
||||
"no-tsan",
|
||||
"no-ubsan",
|
||||
],
|
||||
deps = [
|
||||
":wpilibNewCommands.static",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "DevMain-Java",
|
||||
srcs = ["src/dev/java/edu/wpi/first/wpilibj2/commands/DevMain.java"],
|
||||
main_class = "edu.wpi.first.wpilibj2.commands.DevMain",
|
||||
deps = [
|
||||
"//hal:hal-java",
|
||||
"//ntcore:networktables-java",
|
||||
"//wpimath:wpimath-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
],
|
||||
)
|
||||
@@ -34,8 +34,7 @@ public class ProxyCommand extends Command {
|
||||
* @deprecated This constructor's similarity to {@link DeferredCommand} is confusing and opens
|
||||
* potential footguns for users who do not fully understand the semantics and implications of
|
||||
* proxying, but who simply want runtime construction. Users who do know what they are doing
|
||||
* and need a supplier-constructed proxied command should instead proxy a DeferredCommand
|
||||
* using the <code>asProxy</code> decorator.
|
||||
* and need a supplier-constructed proxied command should instead defer a proxy command.
|
||||
* @see DeferredCommand
|
||||
*/
|
||||
@Deprecated(since = "2025", forRemoval = true)
|
||||
|
||||
@@ -24,6 +24,18 @@ import java.util.function.BooleanSupplier;
|
||||
* <p>This class is provided by the NewCommands VendorDep
|
||||
*/
|
||||
public class Trigger implements BooleanSupplier {
|
||||
/** Functional interface for the body of a trigger binding. */
|
||||
@FunctionalInterface
|
||||
private interface BindingBody {
|
||||
/**
|
||||
* Executes the body of the binding.
|
||||
*
|
||||
* @param previous The previous state of the condition.
|
||||
* @param current The current state of the condition.
|
||||
*/
|
||||
void run(boolean previous, boolean current);
|
||||
}
|
||||
|
||||
private final BooleanSupplier m_condition;
|
||||
private final EventLoop m_loop;
|
||||
|
||||
@@ -49,6 +61,27 @@ public class Trigger implements BooleanSupplier {
|
||||
this(CommandScheduler.getInstance().getDefaultButtonLoop(), condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a binding to the EventLoop.
|
||||
*
|
||||
* @param body The body of the binding to add.
|
||||
*/
|
||||
private void addBinding(BindingBody body) {
|
||||
m_loop.bind(
|
||||
new Runnable() {
|
||||
private boolean m_previous = m_condition.getAsBoolean();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean current = m_condition.getAsBoolean();
|
||||
|
||||
body.run(m_previous, current);
|
||||
|
||||
m_previous = current;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the command when the condition changes.
|
||||
*
|
||||
@@ -57,19 +90,10 @@ public class Trigger implements BooleanSupplier {
|
||||
*/
|
||||
public Trigger onChange(Command command) {
|
||||
requireNonNullParam(command, "command", "onChange");
|
||||
m_loop.bind(
|
||||
new Runnable() {
|
||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean pressed = m_condition.getAsBoolean();
|
||||
|
||||
if (m_pressedLast != pressed) {
|
||||
command.schedule();
|
||||
}
|
||||
|
||||
m_pressedLast = pressed;
|
||||
addBinding(
|
||||
(previous, current) -> {
|
||||
if (previous != current) {
|
||||
command.schedule();
|
||||
}
|
||||
});
|
||||
return this;
|
||||
@@ -83,19 +107,10 @@ public class Trigger implements BooleanSupplier {
|
||||
*/
|
||||
public Trigger onTrue(Command command) {
|
||||
requireNonNullParam(command, "command", "onTrue");
|
||||
m_loop.bind(
|
||||
new Runnable() {
|
||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean pressed = m_condition.getAsBoolean();
|
||||
|
||||
if (!m_pressedLast && pressed) {
|
||||
command.schedule();
|
||||
}
|
||||
|
||||
m_pressedLast = pressed;
|
||||
addBinding(
|
||||
(previous, current) -> {
|
||||
if (!previous && current) {
|
||||
command.schedule();
|
||||
}
|
||||
});
|
||||
return this;
|
||||
@@ -109,19 +124,10 @@ public class Trigger implements BooleanSupplier {
|
||||
*/
|
||||
public Trigger onFalse(Command command) {
|
||||
requireNonNullParam(command, "command", "onFalse");
|
||||
m_loop.bind(
|
||||
new Runnable() {
|
||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean pressed = m_condition.getAsBoolean();
|
||||
|
||||
if (m_pressedLast && !pressed) {
|
||||
command.schedule();
|
||||
}
|
||||
|
||||
m_pressedLast = pressed;
|
||||
addBinding(
|
||||
(previous, current) -> {
|
||||
if (previous && !current) {
|
||||
command.schedule();
|
||||
}
|
||||
});
|
||||
return this;
|
||||
@@ -139,21 +145,12 @@ public class Trigger implements BooleanSupplier {
|
||||
*/
|
||||
public Trigger whileTrue(Command command) {
|
||||
requireNonNullParam(command, "command", "whileTrue");
|
||||
m_loop.bind(
|
||||
new Runnable() {
|
||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean pressed = m_condition.getAsBoolean();
|
||||
|
||||
if (!m_pressedLast && pressed) {
|
||||
command.schedule();
|
||||
} else if (m_pressedLast && !pressed) {
|
||||
command.cancel();
|
||||
}
|
||||
|
||||
m_pressedLast = pressed;
|
||||
addBinding(
|
||||
(previous, current) -> {
|
||||
if (!previous && current) {
|
||||
command.schedule();
|
||||
} else if (previous && !current) {
|
||||
command.cancel();
|
||||
}
|
||||
});
|
||||
return this;
|
||||
@@ -171,21 +168,12 @@ public class Trigger implements BooleanSupplier {
|
||||
*/
|
||||
public Trigger whileFalse(Command command) {
|
||||
requireNonNullParam(command, "command", "whileFalse");
|
||||
m_loop.bind(
|
||||
new Runnable() {
|
||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean pressed = m_condition.getAsBoolean();
|
||||
|
||||
if (m_pressedLast && !pressed) {
|
||||
command.schedule();
|
||||
} else if (!m_pressedLast && pressed) {
|
||||
command.cancel();
|
||||
}
|
||||
|
||||
m_pressedLast = pressed;
|
||||
addBinding(
|
||||
(previous, current) -> {
|
||||
if (previous && !current) {
|
||||
command.schedule();
|
||||
} else if (!previous && current) {
|
||||
command.cancel();
|
||||
}
|
||||
});
|
||||
return this;
|
||||
@@ -199,23 +187,14 @@ public class Trigger implements BooleanSupplier {
|
||||
*/
|
||||
public Trigger toggleOnTrue(Command command) {
|
||||
requireNonNullParam(command, "command", "toggleOnTrue");
|
||||
m_loop.bind(
|
||||
new Runnable() {
|
||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean pressed = m_condition.getAsBoolean();
|
||||
|
||||
if (!m_pressedLast && pressed) {
|
||||
if (command.isScheduled()) {
|
||||
command.cancel();
|
||||
} else {
|
||||
command.schedule();
|
||||
}
|
||||
addBinding(
|
||||
(previous, current) -> {
|
||||
if (!previous && current) {
|
||||
if (command.isScheduled()) {
|
||||
command.cancel();
|
||||
} else {
|
||||
command.schedule();
|
||||
}
|
||||
|
||||
m_pressedLast = pressed;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
@@ -229,23 +208,14 @@ public class Trigger implements BooleanSupplier {
|
||||
*/
|
||||
public Trigger toggleOnFalse(Command command) {
|
||||
requireNonNullParam(command, "command", "toggleOnFalse");
|
||||
m_loop.bind(
|
||||
new Runnable() {
|
||||
private boolean m_pressedLast = m_condition.getAsBoolean();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean pressed = m_condition.getAsBoolean();
|
||||
|
||||
if (m_pressedLast && !pressed) {
|
||||
if (command.isScheduled()) {
|
||||
command.cancel();
|
||||
} else {
|
||||
command.schedule();
|
||||
}
|
||||
addBinding(
|
||||
(previous, current) -> {
|
||||
if (previous && !current) {
|
||||
if (command.isScheduled()) {
|
||||
command.cancel();
|
||||
} else {
|
||||
command.schedule();
|
||||
}
|
||||
|
||||
m_pressedLast = pressed;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
|
||||
@@ -15,159 +15,117 @@ using namespace frc2;
|
||||
|
||||
Trigger::Trigger(const Trigger& other) = default;
|
||||
|
||||
void Trigger::AddBinding(wpi::unique_function<void(bool, bool)>&& body) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
body = std::move(body)]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
body(previous, current);
|
||||
|
||||
previous = current;
|
||||
});
|
||||
}
|
||||
|
||||
Trigger Trigger::OnChange(Command* command) {
|
||||
m_loop->Bind(
|
||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
if (previous != current) {
|
||||
command->Schedule();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
AddBinding([command](bool previous, bool current) {
|
||||
if (previous != current) {
|
||||
command->Schedule();
|
||||
}
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::OnChange(CommandPtr&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::move(command)]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||
if (previous != current) {
|
||||
command.Schedule();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::OnTrue(Command* command) {
|
||||
m_loop->Bind(
|
||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
if (!previous && current) {
|
||||
command->Schedule();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
AddBinding([command](bool previous, bool current) {
|
||||
if (!previous && current) {
|
||||
command->Schedule();
|
||||
}
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::OnTrue(CommandPtr&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::move(command)]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||
if (!previous && current) {
|
||||
command.Schedule();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::OnFalse(Command* command) {
|
||||
m_loop->Bind(
|
||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
if (previous && !current) {
|
||||
command->Schedule();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
AddBinding([command](bool previous, bool current) {
|
||||
if (previous && !current) {
|
||||
command->Schedule();
|
||||
}
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::OnFalse(CommandPtr&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::move(command)]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||
if (previous && !current) {
|
||||
command.Schedule();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::WhileTrue(Command* command) {
|
||||
m_loop->Bind(
|
||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
if (!previous && current) {
|
||||
command->Schedule();
|
||||
} else if (previous && !current) {
|
||||
command->Cancel();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
AddBinding([command](bool previous, bool current) {
|
||||
if (!previous && current) {
|
||||
command->Schedule();
|
||||
} else if (previous && !current) {
|
||||
command->Cancel();
|
||||
}
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::WhileTrue(CommandPtr&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::move(command)]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||
if (!previous && current) {
|
||||
command.Schedule();
|
||||
} else if (previous && !current) {
|
||||
command.Cancel();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::WhileFalse(Command* command) {
|
||||
m_loop->Bind(
|
||||
[condition = m_condition, previous = m_condition(), command]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
if (previous && !current) {
|
||||
command->Schedule();
|
||||
} else if (!previous && current) {
|
||||
command->Cancel();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
AddBinding([command](bool previous, bool current) {
|
||||
if (previous && !current) {
|
||||
command->Schedule();
|
||||
} else if (!previous && current) {
|
||||
command->Cancel();
|
||||
}
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::WhileFalse(CommandPtr&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::move(command)]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||
if (!previous && current) {
|
||||
command.Schedule();
|
||||
} else if (previous && !current) {
|
||||
command.Cancel();
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::ToggleOnTrue(Command* command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = command]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command](bool previous, bool current) {
|
||||
if (!previous && current) {
|
||||
if (command->IsScheduled()) {
|
||||
command->Cancel();
|
||||
@@ -175,17 +133,12 @@ Trigger Trigger::ToggleOnTrue(Command* command) {
|
||||
command->Schedule();
|
||||
}
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::ToggleOnTrue(CommandPtr&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::move(command)]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||
if (!previous && current) {
|
||||
if (command.IsScheduled()) {
|
||||
command.Cancel();
|
||||
@@ -193,17 +146,12 @@ Trigger Trigger::ToggleOnTrue(CommandPtr&& command) {
|
||||
command.Schedule();
|
||||
}
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::ToggleOnFalse(Command* command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = command]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command](bool previous, bool current) {
|
||||
if (previous && !current) {
|
||||
if (command->IsScheduled()) {
|
||||
command->Cancel();
|
||||
@@ -211,17 +159,12 @@ Trigger Trigger::ToggleOnFalse(Command* command) {
|
||||
command->Schedule();
|
||||
}
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
Trigger Trigger::ToggleOnFalse(CommandPtr&& command) {
|
||||
m_loop->Bind([condition = m_condition, previous = m_condition(),
|
||||
command = std::move(command)]() mutable {
|
||||
bool current = condition();
|
||||
|
||||
AddBinding([command = std::move(command)](bool previous, bool current) {
|
||||
if (previous && !current) {
|
||||
if (command.IsScheduled()) {
|
||||
command.Cancel();
|
||||
@@ -229,8 +172,6 @@ Trigger Trigger::ToggleOnFalse(CommandPtr&& command) {
|
||||
command.Schedule();
|
||||
}
|
||||
}
|
||||
|
||||
previous = current;
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -41,12 +41,11 @@ class ProxyCommand : public CommandHelper<Command, ProxyCommand> {
|
||||
* confusing and opens potential footguns for users who do not fully
|
||||
* understand the semantics and implications of proxying, but who simply want
|
||||
* runtime construction. Users who do know what they are doing and need a
|
||||
* supplier-constructed proxied command should instead proxy a DeferredCommand
|
||||
* using the <code>AsProxy</code> decorator.
|
||||
* supplier-constructed proxied command should instead defer a proxy command.
|
||||
* @see DeferredCommand
|
||||
*/
|
||||
WPI_IGNORE_DEPRECATED
|
||||
[[deprecated("Proxy a DeferredCommand instead")]]
|
||||
[[deprecated("Defer a proxy command instead.")]]
|
||||
explicit ProxyCommand(wpi::unique_function<Command*()> supplier);
|
||||
|
||||
/**
|
||||
@@ -62,11 +61,10 @@ class ProxyCommand : public CommandHelper<Command, ProxyCommand> {
|
||||
* confusing and opens potential footguns for users who do not fully
|
||||
* understand the semantics and implications of proxying, but who simply want
|
||||
* runtime construction. Users who do know what they are doing and need a
|
||||
* supplier-constructed proxied command should instead proxy a DeferredCommand
|
||||
* using the <code>AsProxy</code> decorator.
|
||||
* supplier-constructed proxied command should instead defer a proxy command.
|
||||
* @see DeferredCommand
|
||||
*/
|
||||
[[deprecated("Proxy a DeferredCommand instead")]]
|
||||
[[deprecated("Defer a proxy command instead.")]]
|
||||
explicit ProxyCommand(wpi::unique_function<CommandPtr()> supplier);
|
||||
WPI_UNIGNORE_DEPRECATED
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <frc/event/EventLoop.h>
|
||||
#include <frc/filter/Debouncer.h>
|
||||
#include <units/time.h>
|
||||
#include <wpi/FunctionExtras.h>
|
||||
|
||||
#include "frc2/command/Command.h"
|
||||
#include "frc2/command/CommandScheduler.h"
|
||||
@@ -291,6 +292,13 @@ class Trigger {
|
||||
bool Get() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Adds a binding to the EventLoop.
|
||||
*
|
||||
* @param body The body of the binding to add.
|
||||
*/
|
||||
void AddBinding(wpi::unique_function<void(bool, bool)>&& body);
|
||||
|
||||
frc::EventLoop* m_loop;
|
||||
std::function<bool()> m_condition;
|
||||
};
|
||||
|
||||
80
wpilibc/BUILD.bazel
Normal file
80
wpilibc/BUILD.bazel
Normal file
@@ -0,0 +1,80 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load("//shared/bazel/rules/gen:gen-version-file.bzl", "generate_version_file")
|
||||
|
||||
generate_version_file(
|
||||
name = "generate-version",
|
||||
output_file = "WPILibVersion.cpp",
|
||||
template = "src/generate/WPILibVersion.cpp.in",
|
||||
visibility = ["//wpilibc:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "generated_cc_headers",
|
||||
hdrs = glob(["src/generated/main/native/include/**"]),
|
||||
includes = ["src/generated/main/native/include"],
|
||||
strip_include_prefix = "src/generated/main/native/include",
|
||||
visibility = ["//wpilibc:__subpackages__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "generated_cc_source",
|
||||
srcs = glob(
|
||||
["src/generated/main/native/cpp/**"],
|
||||
exclude = ["src/generated/main/native/cpp/jni/**"],
|
||||
),
|
||||
visibility = ["//wpilibc:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "wpilibc.static",
|
||||
srcs = [
|
||||
":generate-version",
|
||||
] + glob([
|
||||
"src/main/native/cppcs/**",
|
||||
"src/main/native/cpp/**",
|
||||
]) + [":generated_cc_source"],
|
||||
hdrs = glob(["src/main/native/include/**"]),
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":generated_cc_headers",
|
||||
"//cameraserver:cameraserver.static",
|
||||
"//cscore:cscore.static",
|
||||
"//hal:wpiHal.static",
|
||||
"//ntcore:ntcore.static",
|
||||
"//wpimath:wpimath.static",
|
||||
"//wpinet:wpinet.static",
|
||||
"//wpiutil:wpiutil.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "test-headers",
|
||||
testonly = True,
|
||||
hdrs = glob(["src/test/native/include/**"]),
|
||||
includes = ["src/test/native/include"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "wpilibc-test",
|
||||
size = "small",
|
||||
srcs = glob(["src/test/native/cpp/**"]),
|
||||
tags = [
|
||||
"no-asan",
|
||||
"no-tsan",
|
||||
"no-ubsan",
|
||||
],
|
||||
deps = [
|
||||
":test-headers",
|
||||
":wpilibc.static",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
":wpilibc.static",
|
||||
],
|
||||
)
|
||||
@@ -759,10 +759,11 @@
|
||||
},
|
||||
{
|
||||
"name": "SimpleDifferentialDriveSimulation",
|
||||
"description": "Simulate a differential drivetrain and follow trajectories with LTV unicycle controller (non-command-based).",
|
||||
"description": "Simulate a differential drivetrain and follow trajectories with LTVUnicycleController (non-command-based).",
|
||||
"tags": [
|
||||
"Differential Drive",
|
||||
"State-Space",
|
||||
"LTVUnicycleController",
|
||||
"Path Following",
|
||||
"Trajectory",
|
||||
"Encoder",
|
||||
|
||||
24
wpilibcIntegrationTests/BUILD.bazel
Normal file
24
wpilibcIntegrationTests/BUILD.bazel
Normal file
@@ -0,0 +1,24 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
|
||||
|
||||
ATHENA_SOURCES = glob(["src/main/native/cpp/**"])
|
||||
|
||||
NON_ATHENA_SOURCES = glob(["src/main/native/dt/**"])
|
||||
|
||||
cc_library(
|
||||
name = "test_headers",
|
||||
hdrs = glob(["src/main/native/include/**"]),
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "wpilibcIntegrationTests",
|
||||
srcs = select({
|
||||
"@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ATHENA_SOURCES,
|
||||
"//conditions:default": NON_ATHENA_SOURCES,
|
||||
}),
|
||||
deps = [
|
||||
":test_headers",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
"//wpilibc:wpilibc.static",
|
||||
],
|
||||
)
|
||||
@@ -650,10 +650,11 @@
|
||||
},
|
||||
{
|
||||
"name": "SimpleDifferentialDriveSimulation",
|
||||
"description": "Simulate a differential drivetrain and follow trajectories with LTV unicycle controller (non-command-based).",
|
||||
"description": "Simulate a differential drivetrain and follow trajectories with LTVUnicycleController (non-command-based).",
|
||||
"tags": [
|
||||
"Differential Drive",
|
||||
"State-Space",
|
||||
"LTVUnicycleController",
|
||||
"Path Following",
|
||||
"Trajectory",
|
||||
"Encoder",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
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")
|
||||
|
||||
@@ -7,6 +8,76 @@ filegroup(
|
||||
visibility = ["//wpimath:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "eigen-headers",
|
||||
hdrs = glob([
|
||||
"src/main/native/thirdparty/eigen/include/**",
|
||||
]),
|
||||
includes = ["src/main/native/thirdparty/eigen/include"],
|
||||
strip_include_prefix = "src/main/native/thirdparty/eigen/include",
|
||||
visibility = ["//wpimath:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "gcem",
|
||||
hdrs = glob([
|
||||
"src/main/native/thirdparty/gcem/include/**",
|
||||
]),
|
||||
includes = ["src/main/native/thirdparty/gcem/include"],
|
||||
strip_include_prefix = "src/main/native/thirdparty/gcem/include",
|
||||
visibility = ["//wpimath:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "sleipnir-headers",
|
||||
hdrs = glob([
|
||||
"src/main/native/thirdparty/sleipnir/include/**/*.hpp",
|
||||
]),
|
||||
includes = ["src/main/native/thirdparty/sleipnir/include"],
|
||||
strip_include_prefix = "src/main/native/thirdparty/sleipnir/include",
|
||||
visibility = ["//wpimath:__subpackages__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "sleipnir-srcs",
|
||||
srcs = glob(["src/main/native/thirdparty/sleipnir/src/**"]),
|
||||
visibility = ["//wpimath:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "nanopb-generated-headers",
|
||||
hdrs = glob(["src/generated/main/native/cpp/**/*.h"]),
|
||||
includes = ["src/generated/main/native/cpp"],
|
||||
strip_include_prefix = "src/generated/main/native/cpp",
|
||||
visibility = ["//wpiutil:__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "wpimath.static",
|
||||
srcs = glob(
|
||||
[
|
||||
"src/main/native/cpp/**",
|
||||
"src/generated/main/native/cpp/**/*.cpp",
|
||||
],
|
||||
exclude = ["src/main/native/cpp/jni/**"],
|
||||
) + [":sleipnir-srcs"],
|
||||
hdrs = glob(["src/main/native/include/**"]),
|
||||
defines = ["WPILIB_EXPORTS"],
|
||||
includes = [
|
||||
"src/main/native/include",
|
||||
"src/main/native/thirdparty/sleipnir/src",
|
||||
],
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":eigen-headers",
|
||||
":gcem",
|
||||
":nanopb-generated-headers",
|
||||
":sleipnir-headers",
|
||||
"//wpiutil:wpiutil.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "wpimath-java",
|
||||
srcs = [":generated_java"] + glob(["src/main/java/**/*.java"]),
|
||||
@@ -24,6 +95,40 @@ java_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "test_headers",
|
||||
hdrs = glob([
|
||||
"src/test/native/include/**",
|
||||
]),
|
||||
strip_include_prefix = "src/test/native/include",
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "wpimath-cpp-test",
|
||||
size = "small",
|
||||
srcs = glob([
|
||||
"src/test/native/cpp/**/*.cpp",
|
||||
"src/test/native/cpp/**/*.h",
|
||||
]),
|
||||
tags = [
|
||||
"no-bullseye",
|
||||
"no-raspi",
|
||||
],
|
||||
deps = [
|
||||
":test_headers",
|
||||
":wpimath.static",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
":wpimath.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "DevMain-Java",
|
||||
srcs = ["src/dev/java/edu/wpi/first/math/DevMain.java"],
|
||||
|
||||
@@ -80,6 +80,22 @@ public class WPINetJNI {
|
||||
*/
|
||||
public static native void removePortForwarder(int port);
|
||||
|
||||
/**
|
||||
* Create a web server at the given port. Note that local ports less than 1024 won't work as a
|
||||
* normal user.
|
||||
*
|
||||
* @param port local port number
|
||||
* @param path local path to document root
|
||||
*/
|
||||
public static native void startWebServer(int port, String path);
|
||||
|
||||
/**
|
||||
* Stop web server running at the given port.
|
||||
*
|
||||
* @param port local port number
|
||||
*/
|
||||
public static native void stopWebServer(int port);
|
||||
|
||||
/**
|
||||
* Creates a MulticastServiceAnnouncer.
|
||||
*
|
||||
|
||||
33
wpinet/src/main/java/edu/wpi/first/net/WebServer.java
Normal file
33
wpinet/src/main/java/edu/wpi/first/net/WebServer.java
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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.net;
|
||||
|
||||
/** A web server using the HTTP protocol. */
|
||||
public final class WebServer {
|
||||
private WebServer() {
|
||||
throw new UnsupportedOperationException("This is a utility class!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a web server at the given port. Note that local ports less than 1024 won't work as a
|
||||
* normal user. Also, many ports are blocked by the FRC robot radio; check the game manual for
|
||||
* what is allowed through the radio firewall.
|
||||
*
|
||||
* @param port local port number
|
||||
* @param path local path to document root
|
||||
*/
|
||||
public static void start(int port, String path) {
|
||||
WPINetJNI.startWebServer(port, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop web server running at the given port.
|
||||
*
|
||||
* @param port local port number
|
||||
*/
|
||||
public static void stop(int port) {
|
||||
WPINetJNI.stopWebServer(port);
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,22 @@ std::string_view EscapeURI(std::string_view str, SmallVectorImpl<char>& buf,
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
std::string_view EscapeHTML(std::string_view str, SmallVectorImpl<char>& buf) {
|
||||
buf.clear();
|
||||
for (auto i = str.begin(), end = str.end(); i != end; ++i) {
|
||||
if (*i == '&') {
|
||||
buf.append({'&', 'a', 'm', 'p', ';'});
|
||||
} else if (*i == '<') {
|
||||
buf.append({'&', 'l', 't', ';'});
|
||||
} else if (*i == '>') {
|
||||
buf.append({'&', 'g', 't', ';'});
|
||||
} else {
|
||||
buf.push_back(*i);
|
||||
}
|
||||
}
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
HttpQueryMap::HttpQueryMap(std::string_view query) {
|
||||
SmallVector<std::string_view, 16> queryElems;
|
||||
split(query, queryElems, '&', 100, false);
|
||||
|
||||
396
wpinet/src/main/native/cpp/WebServer.cpp
Normal file
396
wpinet/src/main/native/cpp/WebServer.cpp
Normal file
@@ -0,0 +1,396 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "wpinet/WebServer.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/DenseMap.h>
|
||||
#include <wpi/MemoryBuffer.h>
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/Signal.h>
|
||||
#include <wpi/StringMap.h>
|
||||
#include <wpi/fs.h>
|
||||
#include <wpi/json.h>
|
||||
#include <wpi/print.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
#include "wpinet/EventLoopRunner.h"
|
||||
#include "wpinet/HttpServerConnection.h"
|
||||
#include "wpinet/HttpUtil.h"
|
||||
#include "wpinet/UrlParser.h"
|
||||
#include "wpinet/raw_uv_ostream.h"
|
||||
#include "wpinet/uv/GetAddrInfo.h"
|
||||
#include "wpinet/uv/Stream.h"
|
||||
#include "wpinet/uv/Tcp.h"
|
||||
#include "wpinet/uv/Timer.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
namespace {
|
||||
class MyHttpConnection : public wpi::HttpServerConnection,
|
||||
public std::enable_shared_from_this<MyHttpConnection> {
|
||||
public:
|
||||
explicit MyHttpConnection(std::shared_ptr<wpi::uv::Stream> stream,
|
||||
std::string_view path)
|
||||
: HttpServerConnection{std::move(stream)}, m_path{path} {}
|
||||
|
||||
protected:
|
||||
void ProcessRequest() override;
|
||||
void SendFileResponse(int code, std::string_view codeText,
|
||||
std::string_view contentType, fs::path filename,
|
||||
std::string_view extraHeader = {});
|
||||
|
||||
std::string m_path;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
#ifndef _WIN32
|
||||
namespace {
|
||||
class SendfileReq : public uv::RequestImpl<SendfileReq, uv_fs_t> {
|
||||
public:
|
||||
SendfileReq(uv_file out, uv_file in, int64_t inOffset, size_t len)
|
||||
: m_out(out), m_in(in), m_inOffset(inOffset), m_len(len) {
|
||||
error = [this](uv::Error err) { GetLoop().error(err); };
|
||||
}
|
||||
|
||||
uv::Loop& GetLoop() const {
|
||||
return *static_cast<uv::Loop*>(GetRaw()->loop->data);
|
||||
}
|
||||
|
||||
int Send(uv::Loop& loop) {
|
||||
int err = uv_fs_sendfile(loop.GetRaw(), GetRaw(), m_out, m_in, m_inOffset,
|
||||
m_len, [](uv_fs_t* req) {
|
||||
auto& h = *static_cast<SendfileReq*>(req->data);
|
||||
if (req->result < 0) {
|
||||
h.ReportError(req->result);
|
||||
h.complete();
|
||||
h.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
h.m_inOffset += req->result;
|
||||
h.m_len -= req->result;
|
||||
if (h.m_len == 0) {
|
||||
// done
|
||||
h.complete();
|
||||
h.Release(); // this is always a one-shot
|
||||
return;
|
||||
}
|
||||
|
||||
// need to send more
|
||||
h.Send(h.GetLoop());
|
||||
});
|
||||
if (err < 0) {
|
||||
ReportError(err);
|
||||
complete();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
wpi::sig::Signal<> complete;
|
||||
|
||||
private:
|
||||
uv_file m_out;
|
||||
uv_file m_in;
|
||||
int64_t m_inOffset;
|
||||
size_t m_len;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static void Sendfile(uv::Loop& loop, uv_file out, uv_file in, int64_t inOffset,
|
||||
size_t len, std::function<void()> complete) {
|
||||
auto req = std::make_shared<SendfileReq>(out, in, inOffset, len);
|
||||
if (complete) {
|
||||
req->complete.connect(complete);
|
||||
}
|
||||
int err = req->Send(loop);
|
||||
if (err >= 0) {
|
||||
req->Keep();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string_view GetMimeType(std::string_view ext) {
|
||||
static const wpi::StringMap<std::string> map{
|
||||
{"css", "text/css"},
|
||||
{"csv", "text/csv"},
|
||||
{"gif", "image/gif"},
|
||||
{"htm", "text/html"},
|
||||
{"html", "text/html"},
|
||||
{"ico", "image/vnd.microsoft.icon"},
|
||||
{"jar", "application/java-archive"},
|
||||
{"jpeg", "image/jpeg"},
|
||||
{"jpg", "image/jpeg"},
|
||||
{"js", "text/javascript"},
|
||||
{"json", "text/json"},
|
||||
{"mjs", "text/javascript"},
|
||||
{"pdf", "application/pdf"},
|
||||
{"png", "image/png"},
|
||||
{"sh", "application/x-sh"},
|
||||
{"svg", "image/svg+xml"},
|
||||
{"txt", "text/plain"},
|
||||
{"webp", "image/webp"},
|
||||
{"xhtml", "application/xhtml+xml"},
|
||||
{"xml", "application/xml"},
|
||||
{"zip", "application/zip"},
|
||||
};
|
||||
auto it = map.find(ext);
|
||||
if (it == map.end()) {
|
||||
return "application/octet-stream";
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void MyHttpConnection::SendFileResponse(int code, std::string_view codeText,
|
||||
std::string_view contentType,
|
||||
fs::path filename,
|
||||
std::string_view extraHeader) {
|
||||
#ifdef _WIN32
|
||||
auto membuf = wpi::MemoryBuffer::GetFile(filename.string());
|
||||
if (!membuf) {
|
||||
SendError(404);
|
||||
return;
|
||||
}
|
||||
|
||||
wpi::SmallVector<uv::Buffer, 4> toSend;
|
||||
wpi::raw_uv_ostream os{toSend, 4096};
|
||||
BuildHeader(os, code, codeText, contentType, (*membuf)->size(), extraHeader);
|
||||
SendData(os.bufs(), false);
|
||||
auto buf = (*membuf)->GetBuffer();
|
||||
m_stream.Write(
|
||||
{{buf}}, [closeAfter = !m_keepAlive, stream = &m_stream,
|
||||
membuf = std::shared_ptr{std::move(*membuf)}](auto, uv::Error) {
|
||||
if (closeAfter) {
|
||||
stream->Close();
|
||||
}
|
||||
});
|
||||
#else
|
||||
// open file
|
||||
std::error_code ec;
|
||||
auto infile = fs::OpenFileForRead(filename, ec);
|
||||
if (ec) {
|
||||
SendError(404);
|
||||
return;
|
||||
}
|
||||
int infd = fs::FileToFd(infile, ec, fs::OF_None);
|
||||
if (ec) {
|
||||
fs::CloseFile(infile);
|
||||
SendError(404);
|
||||
return;
|
||||
}
|
||||
|
||||
// get file size
|
||||
auto size = fs::file_size(filename, ec);
|
||||
if (ec) {
|
||||
SendError(404);
|
||||
::close(infd);
|
||||
return;
|
||||
}
|
||||
|
||||
uv_os_fd_t outfd;
|
||||
int err = uv_fileno(m_stream.GetRawHandle(), &outfd);
|
||||
if (err < 0) {
|
||||
m_stream.GetLoopRef().ReportError(err);
|
||||
SendError(404);
|
||||
::close(infd);
|
||||
return;
|
||||
}
|
||||
|
||||
wpi::SmallVector<uv::Buffer, 4> toSend;
|
||||
wpi::raw_uv_ostream os{toSend, 4096};
|
||||
BuildHeader(os, code, codeText, contentType, size, extraHeader);
|
||||
SendData(os.bufs(), false);
|
||||
|
||||
// close after write completes if we aren't keeping alive
|
||||
// since we're using sendfile, set socket to blocking
|
||||
m_stream.SetBlocking(true);
|
||||
Sendfile(m_stream.GetLoopRef(), outfd, infd, 0, size,
|
||||
[infd, closeAfter = !m_keepAlive, stream = &m_stream] {
|
||||
::close(infd);
|
||||
if (closeAfter) {
|
||||
stream->Close();
|
||||
} else {
|
||||
stream->SetBlocking(false);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void MyHttpConnection::ProcessRequest() {
|
||||
// fmt::print(stderr, "HTTP request: '{}'\n", m_request.GetUrl());
|
||||
wpi::UrlParser url{m_request.GetUrl(),
|
||||
m_request.GetMethod() == wpi::HTTP_CONNECT};
|
||||
if (!url.IsValid()) {
|
||||
// failed to parse URL
|
||||
SendError(400);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string_view path;
|
||||
if (url.HasPath()) {
|
||||
path = url.GetPath();
|
||||
}
|
||||
// fmt::print(stderr, "path: \"{}\"\n", path);
|
||||
|
||||
wpi::SmallString<128> pathBuf;
|
||||
bool error;
|
||||
path = UnescapeURI(path, pathBuf, &error);
|
||||
if (error) {
|
||||
SendError(400);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string_view query;
|
||||
if (url.HasQuery()) {
|
||||
query = url.GetQuery();
|
||||
}
|
||||
// fmt::print(stderr, "query: \"{}\"\n", query);
|
||||
HttpQueryMap qmap{query};
|
||||
|
||||
const bool isGET = m_request.GetMethod() == wpi::HTTP_GET;
|
||||
if (isGET && wpi::starts_with(path, '/') && !wpi::contains(path, "..")) {
|
||||
fs::path fullpath = fmt::format("{}{}", m_path, path);
|
||||
std::error_code ec;
|
||||
bool isdir = fs::is_directory(fullpath, ec);
|
||||
if (isdir) {
|
||||
if (!wpi::ends_with(path, '/')) {
|
||||
// redirect to trailing / location
|
||||
SendResponse(301, "Moved Permanently", "text/plain", "",
|
||||
fmt::format("Location: {}/\r\n\r\n", path));
|
||||
return;
|
||||
}
|
||||
// generate directory listing
|
||||
wpi::SmallString<64> formatBuf;
|
||||
if (qmap.Get("format", formatBuf).value_or("") == "json") {
|
||||
wpi::json dirs = wpi::json::array();
|
||||
wpi::json files = wpi::json::array();
|
||||
for (auto&& entry : fs::directory_iterator{fullpath}) {
|
||||
bool subdir = entry.is_directory(ec);
|
||||
std::string name = entry.path().filename().string();
|
||||
if (subdir) {
|
||||
dirs.emplace_back(wpi::json{{"name", std::move(name)}});
|
||||
} else {
|
||||
files.emplace_back(
|
||||
wpi::json{{"name", std::move(name)},
|
||||
{"size", subdir ? 0 : entry.file_size(ec)}});
|
||||
}
|
||||
}
|
||||
SendResponse(
|
||||
200, "OK", "text/json",
|
||||
wpi::json{{"dirs", std::move(dirs)}, {"files", std::move(files)}}
|
||||
.dump());
|
||||
} else {
|
||||
wpi::StringMap<std::string> dirs;
|
||||
wpi::StringMap<std::string> files;
|
||||
for (auto&& entry : fs::directory_iterator{fullpath}) {
|
||||
bool subdir = entry.is_directory(ec);
|
||||
std::string name = entry.path().filename().string();
|
||||
wpi::SmallString<128> nameUriBuf, nameHtmlBuf;
|
||||
if (subdir) {
|
||||
dirs.emplace(
|
||||
name, fmt::format(
|
||||
"<tr><td><a href=\"{}/\">{}/</a></td><td></td></tr>",
|
||||
EscapeURI(name, nameUriBuf),
|
||||
EscapeHTML(name, nameHtmlBuf)));
|
||||
} else {
|
||||
files.emplace(
|
||||
name, fmt::format(
|
||||
"<tr><td><a href=\"{}\">{}</a></td><td>{}</td></tr>",
|
||||
EscapeURI(name, nameUriBuf),
|
||||
EscapeHTML(name, nameHtmlBuf), entry.file_size(ec)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string html = fmt::format(
|
||||
"<html><head><title>{}</title></head><body>"
|
||||
"<table><tr><th>Name</th><th>Size</th></tr>\n",
|
||||
path);
|
||||
for (auto&& str : dirs) {
|
||||
html += str.second;
|
||||
}
|
||||
for (auto&& str : files) {
|
||||
html += str.second;
|
||||
}
|
||||
html += "</table></body></html>";
|
||||
SendResponse(200, "OK", "text/html", html);
|
||||
}
|
||||
} else {
|
||||
wpi::SmallString<128> extraHeadersBuf;
|
||||
wpi::raw_svector_ostream os{extraHeadersBuf};
|
||||
os << "Content-Disposition: filename=\"";
|
||||
os.write_escaped(fullpath.filename().string());
|
||||
os << "\"\r\n";
|
||||
SendFileResponse(200, "OK", GetMimeType(wpi::rsplit(path, '.').second),
|
||||
fullpath, os.str());
|
||||
}
|
||||
} else {
|
||||
SendError(404, "Resource not found");
|
||||
}
|
||||
}
|
||||
|
||||
struct WebServer::Impl {
|
||||
public:
|
||||
EventLoopRunner runner;
|
||||
DenseMap<unsigned int, std::weak_ptr<uv::Tcp>> servers;
|
||||
};
|
||||
|
||||
WebServer::WebServer() : m_impl{new Impl} {}
|
||||
|
||||
WebServer& WebServer::GetInstance() {
|
||||
static WebServer instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void WebServer::Start(unsigned int port, std::string_view path) {
|
||||
m_impl->runner.ExecSync([&](uv::Loop& loop) {
|
||||
auto server = uv::Tcp::Create(loop);
|
||||
if (!server) {
|
||||
wpi::print(stderr, "WebServer: Creating server failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// bind to local port
|
||||
server->Bind("", port);
|
||||
|
||||
// when we get a connection, accept it
|
||||
server->connection.connect(
|
||||
[serverPtr = server.get(), path = std::string{path}] {
|
||||
auto client = serverPtr->Accept();
|
||||
if (!client) {
|
||||
wpi::print(stderr, "WebServer: Connecting to client failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// close on error
|
||||
client->error.connect([clientPtr = client.get()](uv::Error err) {
|
||||
clientPtr->Close();
|
||||
});
|
||||
|
||||
auto conn = std::make_shared<MyHttpConnection>(client, path);
|
||||
client->SetData(conn);
|
||||
});
|
||||
|
||||
// start listening for incoming connections
|
||||
server->Listen();
|
||||
|
||||
m_impl->servers[port] = server;
|
||||
});
|
||||
}
|
||||
|
||||
void WebServer::Stop(unsigned int port) {
|
||||
m_impl->runner.ExecSync([&](uv::Loop& loop) {
|
||||
if (auto server = m_impl->servers.lookup(port).lock()) {
|
||||
server->Close();
|
||||
m_impl->servers.erase(port);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "wpinet/MulticastServiceAnnouncer.h"
|
||||
#include "wpinet/MulticastServiceResolver.h"
|
||||
#include "wpinet/PortForwarder.h"
|
||||
#include "wpinet/WebServer.h"
|
||||
|
||||
using namespace wpi::java;
|
||||
|
||||
@@ -80,6 +81,31 @@ Java_edu_wpi_first_net_WPINetJNI_removePortForwarder
|
||||
wpi::PortForwarder::GetInstance().Remove(port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_net_WPINetJNI
|
||||
* Method: startWebServer
|
||||
* Signature: (ILjava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_net_WPINetJNI_startWebServer
|
||||
(JNIEnv* env, jclass, jint port, jstring path)
|
||||
{
|
||||
wpi::WebServer::GetInstance().Start(static_cast<unsigned int>(port),
|
||||
JStringRef{env, path}.str());
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_net_WPINetJNI
|
||||
* Method: stopWebServer
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_net_WPINetJNI_stopWebServer
|
||||
(JNIEnv* env, jclass, jint port)
|
||||
{
|
||||
wpi::WebServer::GetInstance().Stop(port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_net_WPINetJNI
|
||||
* Method: createMulticastServiceAnnouncer
|
||||
|
||||
@@ -39,6 +39,11 @@ std::string_view UnescapeURI(std::string_view str, SmallVectorImpl<char>& buf,
|
||||
std::string_view EscapeURI(std::string_view str, SmallVectorImpl<char>& buf,
|
||||
bool spacePlus = true);
|
||||
|
||||
// Escape a string for HTML output.
|
||||
// @param buf Buffer for output
|
||||
// @return Escaped string
|
||||
std::string_view EscapeHTML(std::string_view str, SmallVectorImpl<char>& buf);
|
||||
|
||||
// Parse a set of HTTP headers. Saves just the Content-Type and Content-Length
|
||||
// fields.
|
||||
// @param is Input stream
|
||||
|
||||
58
wpinet/src/main/native/include/wpinet/WebServer.h
Normal file
58
wpinet/src/main/native/include/wpinet/WebServer.h
Normal file
@@ -0,0 +1,58 @@
|
||||
// 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.
|
||||
|
||||
#ifndef WPINET_WEBSERVER_H_
|
||||
#define WPINET_WEBSERVER_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* A web server using the HTTP protocol.
|
||||
*/
|
||||
class WebServer {
|
||||
public:
|
||||
WebServer(const WebServer&) = delete;
|
||||
WebServer& operator=(const WebServer&) = delete;
|
||||
|
||||
/**
|
||||
* Get an instance of the WebServer class.
|
||||
*
|
||||
* This is a singleton to guarantee that there is only a single instance
|
||||
* regardless of how many times GetInstance is called.
|
||||
*/
|
||||
static WebServer& GetInstance();
|
||||
|
||||
/**
|
||||
* Create a web server at the given port.
|
||||
* Note that local ports less than 1024 won't work as a normal user. Also,
|
||||
* many ports are blocked by the FRC robot radio; check the game manual for
|
||||
* what is allowed through the radio firewall.
|
||||
*
|
||||
* @param port local port number
|
||||
* @param path local path to document root
|
||||
*/
|
||||
void Start(unsigned int port, std::string_view path);
|
||||
|
||||
/**
|
||||
* Stop web server running at the given port.
|
||||
*
|
||||
* @param port local port number
|
||||
*/
|
||||
void Stop(unsigned int port);
|
||||
|
||||
private:
|
||||
WebServer();
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
|
||||
#endif // WPINET_WEBSERVER_H_
|
||||
@@ -28,7 +28,7 @@ public final class MomentOfInertiaUnit extends PerUnit<AngularMomentumUnit, Angu
|
||||
}
|
||||
|
||||
MomentOfInertiaUnit(
|
||||
PerUnit<AngularMomentumUnit, AngularVelocityUnit> baseUnit,
|
||||
MomentOfInertiaUnit baseUnit,
|
||||
UnaryFunction toBaseConverter,
|
||||
UnaryFunction fromBaseConverter,
|
||||
String name,
|
||||
|
||||
@@ -197,9 +197,9 @@ cc_library(
|
||||
":llvm-srcs",
|
||||
":memory-srcs",
|
||||
":mpack-srcs",
|
||||
":nanopb-srcs",
|
||||
":native-srcs",
|
||||
":protobuf-srcs",
|
||||
":nanopb-srcs",
|
||||
],
|
||||
hdrs = glob(["src/main/native/include/**/*"]),
|
||||
includes = ["src/main/native/include"],
|
||||
@@ -215,8 +215,8 @@ cc_library(
|
||||
":llvm-headers",
|
||||
":memory-headers",
|
||||
":mpack-headers",
|
||||
":protobuf-headers",
|
||||
":nanopb-headers",
|
||||
":protobuf-headers",
|
||||
":sigslot-headers",
|
||||
] + select({
|
||||
"@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@bzlmodrio-ni//libraries/cpp/ni:shared"],
|
||||
|
||||
@@ -16,17 +16,20 @@ public final class RuntimeLoader {
|
||||
* @return A load error message.
|
||||
*/
|
||||
private static String getLoadErrorMessage(String libraryName, UnsatisfiedLinkError ule) {
|
||||
String jvmLocation = ProcessHandle.current().info().command().orElse("Unknown");
|
||||
StringBuilder msg = new StringBuilder(512);
|
||||
msg.append(libraryName)
|
||||
.append(" could not be loaded from path.\n" + "\tattempted to load for platform ")
|
||||
.append(CombinedRuntimeLoader.getPlatformPath())
|
||||
.append("\nLast Load Error: \n")
|
||||
.append(ule.getMessage())
|
||||
.append('\n');
|
||||
.append('\n')
|
||||
.append(String.format("JVM Location: %s\n", jvmLocation));
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
msg.append(
|
||||
"A common cause of this error is missing the C++ runtime.\n"
|
||||
+ "Download the latest at https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads\n");
|
||||
"A common cause of this error is using a JVM with an incorrect MSVC runtime.\n"
|
||||
+ "Ensure you are using the WPILib JVM (The current running JVM is listed above)\n"
|
||||
+ "See https://wpilib.org/jvmruntime for more information\n");
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
54
xrpVendordep/BUILD.bazel
Normal file
54
xrpVendordep/BUILD.bazel
Normal file
@@ -0,0 +1,54 @@
|
||||
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 = "xrp-cpp",
|
||||
srcs = glob([
|
||||
"src/main/native/cpp/**",
|
||||
]),
|
||||
hdrs = glob(["src/main/native/include/**"]),
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//wpilibc:wpilibc.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "xrp-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//hal:hal-java",
|
||||
"//wpilibj",
|
||||
"//wpimath:wpimath-java",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "xrp-cpp-test",
|
||||
size = "small",
|
||||
srcs = glob(["src/test/native/cpp/**"]),
|
||||
deps = [
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
"//wpiutil:wpiutil.static",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "DevMain-Java",
|
||||
srcs = ["src/dev/java/edu/wpi/first/wpilibj/xrp/DevMain.java"],
|
||||
main_class = "edu.wpi.first.wpilibj.xrp.DevMain",
|
||||
deps = [
|
||||
"//hal:hal-java",
|
||||
"//ntcore:networktables-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
],
|
||||
)
|
||||
Reference in New Issue
Block a user