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 452cacfe72a..5ceaa076ad2 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 74362d9a9f1..ab92427001c 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 084f0220f54..a4bfadf2b36 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 static synchronized void forceLoad() throws IOException { */ 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 00000000000..e7a71a5e79a --- /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 92022ee7978..83d9ded426b 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 00000000000..8df876ab30c --- /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 fb59c4d9598..04efdab2044 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 1509a6f1a03..dca5225809e 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 00000000000..ebfb9a36b2b --- /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 8df876ab30c..3e00482b57d 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 | 168 +++++++----------- .../cpp/frc2/command/button/Trigger.cpp | 155 +++++----------- .../include/frc2/command/button/Trigger.h | 8 + 3 files changed, 125 insertions(+), 206 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 d7b1dd08937..8dc3ae52b3d 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 @@ *

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; @@ -50,26 +62,38 @@ public Trigger(BooleanSupplier condition) { } /** - * Starts the command when the condition changes. + * Adds a binding to the EventLoop. * - * @param command the command to start - * @return this trigger, so calls can be chained + * @param body The body of the binding to add. */ - public Trigger onChange(Command command) { - requireNonNullParam(command, "command", "onChange"); + private void addBinding(BindingBody body) { m_loop.bind( new Runnable() { - private boolean m_pressedLast = m_condition.getAsBoolean(); + private boolean m_previous = m_condition.getAsBoolean(); @Override public void run() { - boolean pressed = m_condition.getAsBoolean(); + boolean current = m_condition.getAsBoolean(); - if (m_pressedLast != pressed) { - command.schedule(); - } + body.run(m_previous, current); - m_pressedLast = pressed; + m_previous = current; + } + }); + } + + /** + * Starts the command when the condition changes. + * + * @param command the command to start + * @return this trigger, so calls can be chained + */ + public Trigger onChange(Command command) { + requireNonNullParam(command, "command", "onChange"); + addBinding( + (previous, current) -> { + if (previous != current) { + command.schedule(); } }); return this; @@ -83,19 +107,10 @@ public void run() { */ 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 void run() { */ 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 void run() { */ 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 void run() { */ 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 void run() { */ 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 void run() { */ 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 a3b02d18f3a..00f179da084 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; -Trigger Trigger::OnChange(Command* command) { - m_loop->Bind( - [condition = m_condition, previous = m_condition(), command]() mutable { - bool current = condition(); +void Trigger::AddBinding(wpi::unique_function&& body) { + m_loop->Bind([condition = m_condition, previous = m_condition(), + body = std::move(body)]() mutable { + bool current = condition(); - if (previous != current) { - command->Schedule(); - } + body(previous, current); + + previous = current; + }); +} - previous = current; - }); +Trigger Trigger::OnChange(Command* command) { + 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 a2382631334..9e86b1b7004 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 3e00482b57d..9efd76a1900 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 9463ea1c8f7..644c095cf21 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 ea40670bb0e..8723e307cae 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 3ed52e1bef9..1abd22855bf 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 09c2428dece..8b98519be91 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 5723e815648..aafdeb0bf0e 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 0f1b55c096d..9c738481997 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 @@ private tResourceType() { 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 fa702d0b58f..60267b6cacd 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 2c37cfbe617..0f1271b7bf1 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 f942e01bb08..3b2b9827a54 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 515388ee1aa..efd30cf8e11 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 7225dee1a97..d3235c9e194 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 714427d1045..353effe9dca 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 2d8e0dd6f5d..e485ee63993 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 enum CANDeviceType { 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 247732c8958..7cfe93b4c4d 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 00000000000..2c61be413ac --- /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 8b98519be91..3e550f466e9 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 278e5c84cd8..00000000000 --- 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 12e09da6a58..8bc6c9a28df 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 602b2ed4297..0d7786c2a23 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 00000000000..ea1ef1abe00 --- /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 542f0f3c961..73995c01353 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 a2470f8afe1..d40fb4d2fd9 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 00000000000..a9a8e083ab4 --- /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 499d9912a7c..e7cb686f71b 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 00000000000..05db6b75270 --- /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 00000000000..b5cfc82cfa4 --- /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 00000000000..7cc0913b6e7 --- /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 da12307993e..2aa48df2804 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 691da8d5e6e..a0a50557263 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 00000000000..6add11137ad --- /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 00000000000..c11298d3d57 --- /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 00000000000..c67b2dd969b --- /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 2f650293fdb..7979a8ba1cb 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 6e9318bedff..928fa4e8f3d 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 00000000000..964ea19d70f --- /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 3e550f466e9..00000000000 --- 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