From 782459dff48e84799a4fb1c92ebe0b238bfdbdba Mon Sep 17 00:00:00 2001 From: Thad House Date: Sat, 14 Dec 2024 11:25:27 -0800 Subject: [PATCH 01/16] [wpiutil] Make runtime loader exception message slightly better (#7536) --- .../src/main/java/edu/wpi/first/util/RuntimeLoader.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/wpiutil/src/main/java/edu/wpi/first/util/RuntimeLoader.java b/wpiutil/src/main/java/edu/wpi/first/util/RuntimeLoader.java index 452cacfe72..5ceaa076ad 100644 --- a/wpiutil/src/main/java/edu/wpi/first/util/RuntimeLoader.java +++ b/wpiutil/src/main/java/edu/wpi/first/util/RuntimeLoader.java @@ -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(); } From f9b3efb712da3c9509e3d9368ecba07136026c9a Mon Sep 17 00:00:00 2001 From: Falon <47285315+falOn-Dev@users.noreply.github.com> Date: Sat, 14 Dec 2024 14:26:26 -0500 Subject: [PATCH 02/16] [wpiunits] Refactor MomentOfInertiaUnit constructor to use MomentOfInertiaUnit instead of a Per<> (#7546) --- .../src/main/java/edu/wpi/first/units/MomentOfInertiaUnit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wpiunits/src/main/java/edu/wpi/first/units/MomentOfInertiaUnit.java b/wpiunits/src/main/java/edu/wpi/first/units/MomentOfInertiaUnit.java index 74362d9a9f..ab92427001 100644 --- a/wpiunits/src/main/java/edu/wpi/first/units/MomentOfInertiaUnit.java +++ b/wpiunits/src/main/java/edu/wpi/first/units/MomentOfInertiaUnit.java @@ -28,7 +28,7 @@ public final class MomentOfInertiaUnit extends PerUnit baseUnit, + MomentOfInertiaUnit baseUnit, UnaryFunction toBaseConverter, UnaryFunction fromBaseConverter, String name, From a1b642a4024c15b4804a2bc58aa33db4d2cd42f6 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sat, 14 Dec 2024 12:51:21 -0700 Subject: [PATCH 03/16] [wpinet] Add simple web server (#7527) Also add EscapeHTML to HttpUtil. --- .../java/edu/wpi/first/net/WPINetJNI.java | 16 + .../java/edu/wpi/first/net/WebServer.java | 33 ++ wpinet/src/main/native/cpp/HttpUtil.cpp | 16 + wpinet/src/main/native/cpp/WebServer.cpp | 381 ++++++++++++++++++ wpinet/src/main/native/cpp/jni/WPINetJNI.cpp | 26 ++ .../src/main/native/include/wpinet/HttpUtil.h | 5 + .../main/native/include/wpinet/WebServer.h | 58 +++ 7 files changed, 535 insertions(+) create mode 100644 wpinet/src/main/java/edu/wpi/first/net/WebServer.java create mode 100644 wpinet/src/main/native/cpp/WebServer.cpp create mode 100644 wpinet/src/main/native/include/wpinet/WebServer.h diff --git a/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java b/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java index 084f0220f5..a4bfadf2b3 100644 --- a/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java +++ b/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.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. * diff --git a/wpinet/src/main/java/edu/wpi/first/net/WebServer.java b/wpinet/src/main/java/edu/wpi/first/net/WebServer.java new file mode 100644 index 0000000000..e7a71a5e79 --- /dev/null +++ b/wpinet/src/main/java/edu/wpi/first/net/WebServer.java @@ -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); + } +} diff --git a/wpinet/src/main/native/cpp/HttpUtil.cpp b/wpinet/src/main/native/cpp/HttpUtil.cpp index 92022ee797..83d9ded426 100644 --- a/wpinet/src/main/native/cpp/HttpUtil.cpp +++ b/wpinet/src/main/native/cpp/HttpUtil.cpp @@ -81,6 +81,22 @@ std::string_view EscapeURI(std::string_view str, SmallVectorImpl& buf, return {buf.data(), buf.size()}; } +std::string_view EscapeHTML(std::string_view str, SmallVectorImpl& 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 queryElems; split(query, queryElems, '&', 100, false); diff --git a/wpinet/src/main/native/cpp/WebServer.cpp b/wpinet/src/main/native/cpp/WebServer.cpp new file mode 100644 index 0000000000..8df876ab30 --- /dev/null +++ b/wpinet/src/main/native/cpp/WebServer.cpp @@ -0,0 +1,381 @@ +// 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 +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 { + public: + explicit MyHttpConnection(std::shared_ptr 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 { + 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(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(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 complete) { + auto req = std::make_shared(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 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 toSend; + wpi::raw_uv_ostream os{toSend, 4096}; + BuildHeader(os, code, codeText, contentType, (*membuf)->size(), extraHeader); + SendData(os.bufs(), false); + m_stream.Write( + {{(*membuf)->GetBuffer()}}, + [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 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); + + 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 dirs; + wpi::StringMap 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( + "{}/", + EscapeURI(name, nameUriBuf), + EscapeHTML(name, nameHtmlBuf))); + } else { + files.emplace( + name, fmt::format( + "{}{}", + EscapeURI(name, nameUriBuf), + EscapeHTML(name, nameHtmlBuf), entry.file_size(ec))); + } + } + + std::string html = fmt::format( + "{}" + "\n", + path); + for (auto&& str : dirs) { + html += str.second; + } + for (auto&& str : files) { + html += str.second; + } + html += "
NameSize
"; + SendResponse(200, "OK", "text/html", html); + } + } else { + SendFileResponse(200, "OK", GetMimeType(wpi::rsplit(path, '.').second), + fullpath); + } + } else { + SendError(404, "Resource not found"); + } +} + +struct WebServer::Impl { + public: + EventLoopRunner runner; + DenseMap> 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(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); + } + }); +} diff --git a/wpinet/src/main/native/cpp/jni/WPINetJNI.cpp b/wpinet/src/main/native/cpp/jni/WPINetJNI.cpp index fb59c4d959..04efdab204 100644 --- a/wpinet/src/main/native/cpp/jni/WPINetJNI.cpp +++ b/wpinet/src/main/native/cpp/jni/WPINetJNI.cpp @@ -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(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 diff --git a/wpinet/src/main/native/include/wpinet/HttpUtil.h b/wpinet/src/main/native/include/wpinet/HttpUtil.h index 1509a6f1a0..dca5225809 100644 --- a/wpinet/src/main/native/include/wpinet/HttpUtil.h +++ b/wpinet/src/main/native/include/wpinet/HttpUtil.h @@ -39,6 +39,11 @@ std::string_view UnescapeURI(std::string_view str, SmallVectorImpl& buf, std::string_view EscapeURI(std::string_view str, SmallVectorImpl& 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& buf); + // Parse a set of HTTP headers. Saves just the Content-Type and Content-Length // fields. // @param is Input stream diff --git a/wpinet/src/main/native/include/wpinet/WebServer.h b/wpinet/src/main/native/include/wpinet/WebServer.h new file mode 100644 index 0000000000..ebfb9a36b2 --- /dev/null +++ b/wpinet/src/main/native/include/wpinet/WebServer.h @@ -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 +#include + +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 m_impl; +}; + +} // namespace wpi + +#endif // WPINET_WEBSERVER_H_ From 564c1f2de22bf420c057c7652f7630ee02473cbc Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sun, 15 Dec 2024 00:07:48 -0700 Subject: [PATCH 04/16] [wpinet] WebServer: Fix Windows (#7551) The order of evaluation of parameters is not defined; on Windows, the std::move was executed before the GetBuffer(). --- wpinet/src/main/native/cpp/WebServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wpinet/src/main/native/cpp/WebServer.cpp b/wpinet/src/main/native/cpp/WebServer.cpp index 8df876ab30..3e00482b57 100644 --- a/wpinet/src/main/native/cpp/WebServer.cpp +++ b/wpinet/src/main/native/cpp/WebServer.cpp @@ -163,10 +163,10 @@ void MyHttpConnection::SendFileResponse(int code, std::string_view codeText, 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( - {{(*membuf)->GetBuffer()}}, - [closeAfter = !m_keepAlive, stream = &m_stream, - membuf = std::shared_ptr{std::move(*membuf)}](auto, uv::Error) { + {{buf}}, [closeAfter = !m_keepAlive, stream = &m_stream, + membuf = std::shared_ptr{std::move(*membuf)}](auto, uv::Error) { if (closeAfter) { stream->Close(); } From 70f36cce7e97d9be00a8a9b552a0e549f2ed13ad Mon Sep 17 00:00:00 2001 From: Joseph Eng <91924258+KangarooKoala@users.noreply.github.com> Date: Sat, 14 Dec 2024 23:13:41 -0800 Subject: [PATCH 05/16] [commands] Extract common trigger binding logic (#7550) This makes the logic clearer in the actual binding methods and will hopefully make it less annoying to make changes such as allowing control over initial edges. Also changes Java to use previous and current to match C++. --- .../wpilibj2/command/button/Trigger.java | 172 ++++++++---------- .../cpp/frc2/command/button/Trigger.cpp | 157 +++++----------- .../include/frc2/command/button/Trigger.h | 8 + 3 files changed, 128 insertions(+), 209 deletions(-) diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java index d7b1dd0893..8dc3ae52b3 100644 --- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java +++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java @@ -24,6 +24,18 @@ import java.util.function.BooleanSupplier; *

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; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp index a3b02d18f3..00f179da08 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp @@ -15,159 +15,117 @@ using namespace frc2; Trigger::Trigger(const Trigger& other) = default; +void Trigger::AddBinding(wpi::unique_function&& 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; } diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h index a238263133..9e86b1b700 100644 --- a/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h +++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h @@ -11,6 +11,7 @@ #include #include #include +#include #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&& body); + frc::EventLoop* m_loop; std::function m_condition; }; From 80c391e18278fcb91189a664bb2b2ddaad7eb7a9 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sun, 15 Dec 2024 12:28:08 -0800 Subject: [PATCH 06/16] [wpinet] WebServer: Unescape URI (#7552) Also provide Content-Disposition filename header in response. This fixes e.g. filenames with spaces in them. --- wpinet/src/main/native/cpp/WebServer.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/wpinet/src/main/native/cpp/WebServer.cpp b/wpinet/src/main/native/cpp/WebServer.cpp index 3e00482b57..9efd76a190 100644 --- a/wpinet/src/main/native/cpp/WebServer.cpp +++ b/wpinet/src/main/native/cpp/WebServer.cpp @@ -15,11 +15,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "wpinet/EventLoopRunner.h" #include "wpinet/HttpServerConnection.h" @@ -239,6 +241,14 @@ void MyHttpConnection::ProcessRequest() { } // 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(); @@ -314,8 +324,13 @@ void MyHttpConnection::ProcessRequest() { 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); + fullpath, os.str()); } } else { SendError(404, "Resource not found"); From 6fe5da72894fc94499eb93305941f9c621892747 Mon Sep 17 00:00:00 2001 From: sciencewhiz Date: Wed, 18 Dec 2024 08:20:31 -0800 Subject: [PATCH 07/16] [examples] Fix example json for SimpleDifferentialDriveSimulation (NFC) (#7561) Uses LTVUnicycleController now instead of RAMSETE. --- shared/examplecheck.gradle | 6 +++--- wpilibcExamples/src/main/cpp/examples/examples.json | 4 ++-- .../main/java/edu/wpi/first/wpilibj/examples/examples.json | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/shared/examplecheck.gradle b/shared/examplecheck.gradle index 9463ea1c8f..644c095cf2 100644 --- a/shared/examplecheck.gradle +++ b/shared/examplecheck.gradle @@ -67,9 +67,9 @@ def tagList = [ "SmartDashboard", "Shuffleboard", "Sendable", "DataLog", /* --- Controls --- */ - "Exponential Profile", "PID", "State-Space", "Ramsete", "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", diff --git a/wpilibcExamples/src/main/cpp/examples/examples.json b/wpilibcExamples/src/main/cpp/examples/examples.json index ea40670bb0..8723e307ca 100644 --- a/wpilibcExamples/src/main/cpp/examples/examples.json +++ b/wpilibcExamples/src/main/cpp/examples/examples.json @@ -759,11 +759,11 @@ }, { "name": "SimpleDifferentialDriveSimulation", - "description": "Simulate a differential drivetrain and follow trajectories with RamseteController (non-command-based).", + "description": "Simulate a differential drivetrain and follow trajectories with LTVUnicycleController (non-command-based).", "tags": [ "Differential Drive", "State-Space", - "Ramsete", + "LTVUnicycleController", "Path Following", "Trajectory", "Encoder", diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/examples.json b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/examples.json index 3ed52e1bef..1abd22855b 100644 --- a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/examples.json +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/examples.json @@ -650,11 +650,11 @@ }, { "name": "SimpleDifferentialDriveSimulation", - "description": "Simulate a differential drivetrain and follow trajectories with RamseteController (non-command-based).", + "description": "Simulate a differential drivetrain and follow trajectories with LTVUnicycleController (non-command-based).", "tags": [ "Differential Drive", "State-Space", - "Ramsete", + "LTVUnicycleController", "Path Following", "Trajectory", "Encoder", From 66cce1835c8166f169deaed4fdde51aef9ad03d1 Mon Sep 17 00:00:00 2001 From: Jade Date: Thu, 19 Dec 2024 00:31:02 +0800 Subject: [PATCH 08/16] [ci] Add Buildifier to /format comment command (#7480) Signed-off-by: Jade Turner --- .github/workflows/comment-command.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/comment-command.yml b/.github/workflows/comment-command.yml index 09c2428dec..8b98519be9 100644 --- a/.github/workflows/comment-command.yml +++ b/.github/workflows/comment-command.yml @@ -42,12 +42,24 @@ jobs: with: distribution: 'temurin' java-version: 17 + - name: Set up Go 1.15.x + uses: actions/setup-go@v5 + with: + cache: false + go-version: 1.15.x + id: go + - name: Install Buildifier + run: | + cd $(mktemp -d) + GO111MODULE=on go get github.com/bazelbuild/buildtools/buildifier@6.0.0 - name: Install wpiformat run: pip3 install wpiformat==2024.50 - name: Run wpiformat run: wpiformat - name: Run spotlessApply run: ./gradlew spotlessApply + - name: Run buildifier + run: buildifier -warnings all --lint=fix -r . - name: Commit run: | # Set credentials From e2cbdf9718b37a8749a7831b7a390adc6d3a03e1 Mon Sep 17 00:00:00 2001 From: Jan-Felix Abellera Date: Wed, 18 Dec 2024 10:34:45 -0600 Subject: [PATCH 09/16] [hal] Add usage reporting for REV Servo Hub (#7555) --- hal/src/generate/ResourceType.txt | 1 + hal/src/generated/main/java/edu/wpi/first/hal/FRCNetComm.java | 2 ++ hal/src/generated/main/native/include/hal/FRCUsageReporting.h | 1 + hal/src/generated/main/native/include/hal/UsageReporting.h | 1 + 4 files changed, 5 insertions(+) diff --git a/hal/src/generate/ResourceType.txt b/hal/src/generate/ResourceType.txt index 5723e81564..aafdeb0bf0 100644 --- a/hal/src/generate/ResourceType.txt +++ b/hal/src/generate/ResourceType.txt @@ -124,3 +124,4 @@ kResourceType_Koors40 = 122 kResourceType_ThriftyNova = 123 kResourceType_PWFSEN36005 = 124 kResourceType_LaserShark = 125 +kResourceType_RevServoHub = 126 diff --git a/hal/src/generated/main/java/edu/wpi/first/hal/FRCNetComm.java b/hal/src/generated/main/java/edu/wpi/first/hal/FRCNetComm.java index 0f1b55c096..9c73848199 100644 --- a/hal/src/generated/main/java/edu/wpi/first/hal/FRCNetComm.java +++ b/hal/src/generated/main/java/edu/wpi/first/hal/FRCNetComm.java @@ -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; } /** diff --git a/hal/src/generated/main/native/include/hal/FRCUsageReporting.h b/hal/src/generated/main/native/include/hal/FRCUsageReporting.h index fa702d0b58..60267b6cac 100644 --- a/hal/src/generated/main/native/include/hal/FRCUsageReporting.h +++ b/hal/src/generated/main/native/include/hal/FRCUsageReporting.h @@ -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, diff --git a/hal/src/generated/main/native/include/hal/UsageReporting.h b/hal/src/generated/main/native/include/hal/UsageReporting.h index 2c37cfbe61..0f1271b7bf 100644 --- a/hal/src/generated/main/native/include/hal/UsageReporting.h +++ b/hal/src/generated/main/native/include/hal/UsageReporting.h @@ -146,6 +146,7 @@ typedef enum kResourceType_ThriftyNova = 123, kResourceType_PWFSEN36005 = 124, kResourceType_LaserShark = 125, + kResourceType_RevServoHub = 126, // kResourceType_MaximumID = 255, } tResourceType; From 6e44187ff639a460b9d2143d3badca9dddb19b6f Mon Sep 17 00:00:00 2001 From: Ryan Blue Date: Wed, 18 Dec 2024 11:35:23 -0500 Subject: [PATCH 10/16] [build] cmake: Add wpilibNewCommands and apriltag to developerRobot (#7557) --- developerRobot/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/developerRobot/CMakeLists.txt b/developerRobot/CMakeLists.txt index f942e01bb0..3b2b9827a5 100644 --- a/developerRobot/CMakeLists.txt +++ b/developerRobot/CMakeLists.txt @@ -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) From 156bd71fef8bc85a7f071c1c562c098ef7354f1c Mon Sep 17 00:00:00 2001 From: Jade Date: Thu, 19 Dec 2024 00:46:31 +0800 Subject: [PATCH 11/16] [developerRobot] Workaround Eclipse annotation processor issues (#7537) Signed-off-by: Jade Turner --- developerRobot/build.gradle | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/developerRobot/build.gradle b/developerRobot/build.gradle index 515388ee1a..efd30cf8e1 100644 --- a/developerRobot/build.gradle +++ b/developerRobot/build.gradle @@ -142,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') From f8720a628c87b72bf6ece61d943067768c2d7f2f Mon Sep 17 00:00:00 2001 From: Jade Date: Thu, 19 Dec 2024 13:57:11 +0800 Subject: [PATCH 12/16] [commands] Fix proxy command deprecation docs (#7396) Signed-off-by: Jade Turner Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com> --- .../edu/wpi/first/wpilibj2/command/ProxyCommand.java | 3 +-- .../main/native/include/frc2/command/ProxyCommand.h | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyCommand.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyCommand.java index 7225dee1a9..d3235c9e19 100644 --- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyCommand.java +++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/ProxyCommand.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 asProxy decorator. + * and need a supplier-constructed proxied command should instead defer a proxy command. * @see DeferredCommand */ @Deprecated(since = "2025", forRemoval = true) diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/ProxyCommand.h b/wpilibNewCommands/src/main/native/include/frc2/command/ProxyCommand.h index 714427d104..353effe9dc 100644 --- a/wpilibNewCommands/src/main/native/include/frc2/command/ProxyCommand.h +++ b/wpilibNewCommands/src/main/native/include/frc2/command/ProxyCommand.h @@ -41,12 +41,11 @@ class ProxyCommand : public CommandHelper { * 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 AsProxy 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 supplier); /** @@ -62,11 +61,10 @@ class ProxyCommand : public CommandHelper { * 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 AsProxy 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 supplier); WPI_UNIGNORE_DEPRECATED From cc73236a0698dbfdc44a6236628ac5ba1083226f Mon Sep 17 00:00:00 2001 From: Jan-Felix Abellera Date: Wed, 18 Dec 2024 23:57:34 -0600 Subject: [PATCH 13/16] [hal] Add CAN device type for servo controllers (#7556) --- hal/src/main/java/edu/wpi/first/hal/CANAPITypes.java | 2 ++ hal/src/main/native/include/hal/CANAPITypes.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hal/src/main/java/edu/wpi/first/hal/CANAPITypes.java b/hal/src/main/java/edu/wpi/first/hal/CANAPITypes.java index 2d8e0dd6f5..e485ee6399 100644 --- a/hal/src/main/java/edu/wpi/first/hal/CANAPITypes.java +++ b/hal/src/main/java/edu/wpi/first/hal/CANAPITypes.java @@ -47,6 +47,8 @@ public final class CANAPITypes { kMiscellaneous(10), /** IO breakout. */ kIOBreakout(11), + /** Servo Controller. */ + kServoController(12), /** Firmware update. */ kFirmwareUpdate(31); diff --git a/hal/src/main/native/include/hal/CANAPITypes.h b/hal/src/main/native/include/hal/CANAPITypes.h index 247732c895..7cfe93b4c4 100644 --- a/hal/src/main/native/include/hal/CANAPITypes.h +++ b/hal/src/main/native/include/hal/CANAPITypes.h @@ -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 }; From 38d8929f488e48f743df75fdfa5bec3fb0eda5af Mon Sep 17 00:00:00 2001 From: Gold856 <117957790+Gold856@users.noreply.github.com> Date: Thu, 19 Dec 2024 00:59:47 -0500 Subject: [PATCH 14/16] [ci] Move pregen steps into a composite action (#7474) This ensures that complete uniformity in how the generation scripts are run. All dependencies and scripts are set up in the exact same way, each time. The old pregen_all script has been removed and moved into the composite action to ensure failed scripts will always fail the job. --- .github/actions/pregen/action.yml | 61 +++++++++++++++++++++ .github/workflows/comment-command.yml | 12 +---- .github/workflows/pregen_all.py | 78 --------------------------- .github/workflows/pregenerate.yml | 12 +---- 4 files changed, 65 insertions(+), 98 deletions(-) create mode 100644 .github/actions/pregen/action.yml delete mode 100755 .github/workflows/pregen_all.py diff --git a/.github/actions/pregen/action.yml b/.github/actions/pregen/action.yml new file mode 100644 index 0000000000..2c61be413a --- /dev/null +++ b/.github/actions/pregen/action.yml @@ -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 diff --git a/.github/workflows/comment-command.yml b/.github/workflows/comment-command.yml index 8b98519be9..3e550f466e 100644 --- a/.github/workflows/comment-command.yml +++ b/.github/workflows/comment-command.yml @@ -93,16 +93,8 @@ jobs: 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: Run pregen + uses: ./.github/actions/pregen - name: Commit run: | # Set credentials diff --git a/.github/workflows/pregen_all.py b/.github/workflows/pregen_all.py deleted file mode 100755 index 278e5c84cd..0000000000 --- a/.github/workflows/pregen_all.py +++ /dev/null @@ -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() diff --git a/.github/workflows/pregenerate.yml b/.github/workflows/pregenerate.yml index 12e09da6a5..8bc6c9a28d 100644 --- a/.github/workflows/pregenerate.yml +++ b/.github/workflows/pregenerate.yml @@ -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 From 9ccd73108b9f13bb23b5eeb27e0ba14a3701258b Mon Sep 17 00:00:00 2001 From: PJ Reiniger Date: Thu, 19 Dec 2024 01:00:40 -0500 Subject: [PATCH 15/16] [bazel] MVP for building wpilibc + commands framework (#7231) --- WORKSPACE | 27 ++++- apriltag/BUILD.bazel | 112 ++++++++++++++++++ cameraserver/BUILD.bazel | 29 ++++- cscore/BUILD.bazel | 89 ++++++++++++++ epilogue-processor/BUILD.bazel | 22 ++++ .../epilogue/processor/LoggerGenerator.java | 2 + epilogue-runtime/BUILD.bazel | 12 ++ fieldImages/BUILD.bazel | 31 +++++ romiVendordep/BUILD.bazel | 53 +++++++++ shared/bazel/compiler_flags/osx_flags.rc | 3 + shared/bazel/compiler_flags/roborio_flags.rc | 2 + wpilibNewCommands/BUILD.bazel | 87 ++++++++++++++ wpilibc/BUILD.bazel | 80 +++++++++++++ wpilibcIntegrationTests/BUILD.bazel | 24 ++++ wpimath/BUILD.bazel | 105 ++++++++++++++++ wpiutil/BUILD.bazel | 4 +- xrpVendordep/BUILD.bazel | 54 +++++++++ 17 files changed, 729 insertions(+), 7 deletions(-) create mode 100644 apriltag/BUILD.bazel create mode 100644 epilogue-processor/BUILD.bazel create mode 100644 epilogue-runtime/BUILD.bazel create mode 100644 fieldImages/BUILD.bazel create mode 100644 romiVendordep/BUILD.bazel create mode 100644 wpilibNewCommands/BUILD.bazel create mode 100644 wpilibc/BUILD.bazel create mode 100644 wpilibcIntegrationTests/BUILD.bazel create mode 100644 xrpVendordep/BUILD.bazel diff --git a/WORKSPACE b/WORKSPACE index 602b2ed429..0d7786c2a2 100644 --- a/WORKSPACE +++ b/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() diff --git a/apriltag/BUILD.bazel b/apriltag/BUILD.bazel new file mode 100644 index 0000000000..ea1ef1abe0 --- /dev/null +++ b/apriltag/BUILD.bazel @@ -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"], +) diff --git a/cameraserver/BUILD.bazel b/cameraserver/BUILD.bazel index 542f0f3c96..73995c0135 100644 --- a/cameraserver/BUILD.bazel +++ b/cameraserver/BUILD.bazel @@ -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", ], ) diff --git a/cscore/BUILD.bazel b/cscore/BUILD.bazel index a2470f8afe..d40fb4d2fd 100644 --- a/cscore/BUILD.bazel +++ b/cscore/BUILD.bazel @@ -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"], diff --git a/epilogue-processor/BUILD.bazel b/epilogue-processor/BUILD.bazel new file mode 100644 index 0000000000..a9a8e083ab --- /dev/null +++ b/epilogue-processor/BUILD.bazel @@ -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", + ], +) diff --git a/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/LoggerGenerator.java b/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/LoggerGenerator.java index 499d9912a7..e7cb686f71 100644 --- a/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/LoggerGenerator.java +++ b/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/LoggerGenerator.java @@ -43,6 +43,8 @@ public class LoggerGenerator { LoggerGenerator::isBuiltInJavaMethod; private final ProcessingEnvironment m_processingEnv; private final List m_handlers; + + @SuppressWarnings("BadAnnotationImplementation") private final Logged m_defaultConfig = new Logged() { @Override diff --git a/epilogue-runtime/BUILD.bazel b/epilogue-runtime/BUILD.bazel new file mode 100644 index 0000000000..05db6b7527 --- /dev/null +++ b/epilogue-runtime/BUILD.bazel @@ -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", + ], +) diff --git a/fieldImages/BUILD.bazel b/fieldImages/BUILD.bazel new file mode 100644 index 0000000000..b5cfc82cfa --- /dev/null +++ b/fieldImages/BUILD.bazel @@ -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", + ], +) diff --git a/romiVendordep/BUILD.bazel b/romiVendordep/BUILD.bazel new file mode 100644 index 0000000000..7cc0913b6e --- /dev/null +++ b/romiVendordep/BUILD.bazel @@ -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", + ], +) diff --git a/shared/bazel/compiler_flags/osx_flags.rc b/shared/bazel/compiler_flags/osx_flags.rc index da12307993..2aa48df280 100644 --- a/shared/bazel/compiler_flags/osx_flags.rc +++ b/shared/bazel/compiler_flags/osx_flags.rc @@ -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 diff --git a/shared/bazel/compiler_flags/roborio_flags.rc b/shared/bazel/compiler_flags/roborio_flags.rc index 691da8d5e6..a0a5055726 100644 --- a/shared/bazel/compiler_flags/roborio_flags.rc +++ b/shared/bazel/compiler_flags/roborio_flags.rc @@ -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 diff --git a/wpilibNewCommands/BUILD.bazel b/wpilibNewCommands/BUILD.bazel new file mode 100644 index 0000000000..6add11137a --- /dev/null +++ b/wpilibNewCommands/BUILD.bazel @@ -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", + ], +) diff --git a/wpilibc/BUILD.bazel b/wpilibc/BUILD.bazel new file mode 100644 index 0000000000..c11298d3d5 --- /dev/null +++ b/wpilibc/BUILD.bazel @@ -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", + ], +) diff --git a/wpilibcIntegrationTests/BUILD.bazel b/wpilibcIntegrationTests/BUILD.bazel new file mode 100644 index 0000000000..c67b2dd969 --- /dev/null +++ b/wpilibcIntegrationTests/BUILD.bazel @@ -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", + ], +) diff --git a/wpimath/BUILD.bazel b/wpimath/BUILD.bazel index 2f650293fd..7979a8ba1c 100644 --- a/wpimath/BUILD.bazel +++ b/wpimath/BUILD.bazel @@ -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"], diff --git a/wpiutil/BUILD.bazel b/wpiutil/BUILD.bazel index 6e9318bedf..928fa4e8f3 100644 --- a/wpiutil/BUILD.bazel +++ b/wpiutil/BUILD.bazel @@ -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"], diff --git a/xrpVendordep/BUILD.bazel b/xrpVendordep/BUILD.bazel new file mode 100644 index 0000000000..964ea19d70 --- /dev/null +++ b/xrpVendordep/BUILD.bazel @@ -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", + ], +) From f46c81cfe305ffd96f3a9b757660932790fc6c1f Mon Sep 17 00:00:00 2001 From: Ryan Blue Date: Thu, 19 Dec 2024 21:53:17 -0500 Subject: [PATCH 16/16] [ci] Delete comment command (#7566) --- .github/workflows/comment-command.yml | 105 -------------------------- 1 file changed, 105 deletions(-) delete mode 100644 .github/workflows/comment-command.yml diff --git a/.github/workflows/comment-command.yml b/.github/workflows/comment-command.yml deleted file mode 100644 index 3e550f466e..0000000000 --- a/.github/workflows/comment-command.yml +++ /dev/null @@ -1,105 +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: Set up Go 1.15.x - uses: actions/setup-go@v5 - with: - cache: false - go-version: 1.15.x - id: go - - name: Install Buildifier - run: | - cd $(mktemp -d) - GO111MODULE=on go get github.com/bazelbuild/buildtools/buildifier@6.0.0 - - name: Install wpiformat - run: pip3 install wpiformat==2024.50 - - name: Run wpiformat - run: wpiformat - - name: Run spotlessApply - run: ./gradlew spotlessApply - - name: Run buildifier - run: buildifier -warnings all --lint=fix -r . - - 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: Run pregen - uses: ./.github/actions/pregen - - 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