diff --git a/cameraserver/multiCameraServer/build.gradle b/cameraserver/multiCameraServer/build.gradle index 4aafd266c7..acd898d542 100644 --- a/cameraserver/multiCameraServer/build.gradle +++ b/cameraserver/multiCameraServer/build.gradle @@ -59,6 +59,9 @@ model { lib project: ':cscore', library: 'cscore', linkage: 'static' lib project: ':wpinet', library: 'wpinet', linkage: 'static' lib project: ':wpiutil', library: 'wpiutil', linkage: 'static' + if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(binary, 'ni_link_libraries', 'ni_runtime_libraries') + } } } } diff --git a/cscore/build.gradle b/cscore/build.gradle index afbef932df..a8db68e78b 100644 --- a/cscore/build.gradle +++ b/cscore/build.gradle @@ -215,6 +215,9 @@ model { it.linker.args << '-lGL' } } + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } } sources { cpp { @@ -233,6 +236,9 @@ model { lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' lib project: ':wpinet', library: 'wpinet', linkage: 'shared' lib library: 'cscore', linkage: 'shared' + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } } sources { cpp { diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp index 8d3075e026..3497ba3a09 100644 --- a/hal/src/main/native/athena/HAL.cpp +++ b/hal/src/main/native/athena/HAL.cpp @@ -516,8 +516,9 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) { setNewDataSem(nullptr); }); - nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass = - nLoadOut::getTargetClass(); + // Setup WPI_Now to use FPGA timestamp + // this also sets nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass + wpi::impl::SetupNowRio(); int32_t status = 0; global.reset(tGlobal::create(&status)); @@ -543,21 +544,6 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) { return false; } - // Set WPI_Now to use FPGA timestamp - wpi::SetNowImpl([]() -> uint64_t { - int32_t status = 0; - uint64_t rv = HAL_GetFPGATime(&status); - if (status != 0) { - fmt::print(stderr, - "Call to HAL_GetFPGATime failed in wpi::Now() with status {}. " - "Initialization might have failed. Time will not be correct\n", - status); - std::fflush(stderr); - return 0u; - } - return rv; - }); - hal::WaitForInitialPacket(); initialized = true; diff --git a/ntcore/src/dev/native/cpp/main.cpp b/ntcore/src/dev/native/cpp/main.cpp index 66418cc20a..6e43fdb41e 100644 --- a/ntcore/src/dev/native/cpp/main.cpp +++ b/ntcore/src/dev/native/cpp/main.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "ntcore.h" #include "ntcore_cpp.h" @@ -23,6 +24,8 @@ void bench2(); void stress(); int main(int argc, char* argv[]) { + wpi::impl::SetupNowRio(); + if (argc == 2 && std::string_view{argv[1]} == "bench") { bench(); return EXIT_SUCCESS; diff --git a/ntcore/src/test/native/cpp/main.cpp b/ntcore/src/test/native/cpp/main.cpp index 6d37027c53..0f060b0e92 100644 --- a/ntcore/src/test/native/cpp/main.cpp +++ b/ntcore/src/test/native/cpp/main.cpp @@ -4,10 +4,13 @@ #include +#include + #include "gmock/gmock.h" #include "ntcore.h" int main(int argc, char** argv) { + wpi::impl::SetupNowRio(); nt::AddLogger(nt::GetDefaultInstance(), 0, UINT_MAX, [](auto& event) { if (auto msg = event.GetLogMessage()) { std::fputs(msg->message.c_str(), stderr); diff --git a/shared/javacpp/setupBuild.gradle b/shared/javacpp/setupBuild.gradle index 5977ce7d90..0c1ad31db6 100644 --- a/shared/javacpp/setupBuild.gradle +++ b/shared/javacpp/setupBuild.gradle @@ -78,6 +78,18 @@ model { } } } + binaries.all { + lib library: nativeName, linkage: 'shared' + if (!project.hasProperty('noWpiutil')) { + lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } + } + if (project.hasProperty('exeSplitSetup')) { + exeSplitSetup(it) + } + } } } testSuites { @@ -104,6 +116,15 @@ model { binaries { withType(GoogleTestTestSuiteBinarySpec) { lib library: nativeName, linkage: 'shared' + if (!project.hasProperty('noWpiutil')) { + lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } + } + if (project.hasProperty('exeSplitSetup')) { + exeSplitSetup(it) + } } } tasks { diff --git a/shared/jni/setupBuild.gradle b/shared/jni/setupBuild.gradle index 7e5d04d5a7..cec30b7af3 100644 --- a/shared/jni/setupBuild.gradle +++ b/shared/jni/setupBuild.gradle @@ -198,7 +198,6 @@ model { targetBuildTypes 'debug' sources { cpp { - source { srcDirs 'src/dev/native/cpp' include '**/*.cpp' @@ -217,6 +216,9 @@ model { if (!project.hasProperty('noWpiutil')) { lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' lib project: ':wpiutil', library: 'wpiutilJNIShared', linkage: 'shared' + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } } if (project.hasProperty('exeSplitSetup')) { exeSplitSetup(it) @@ -253,6 +255,9 @@ model { lib library: nativeName, linkage: 'shared' if (!project.hasProperty('noWpiutil')) { lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } } if (project.hasProperty('exeSplitSetup')) { exeSplitSetup(it) diff --git a/wpinet/build.gradle b/wpinet/build.gradle index d79d359078..b8b86e49c4 100644 --- a/wpinet/build.gradle +++ b/wpinet/build.gradle @@ -231,6 +231,9 @@ model { binaries.all { lib library: 'wpinet', linkage: 'shared' lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } } sources { cpp { @@ -256,6 +259,9 @@ model { binaries.all { binary -> lib project: ':wpinet', library: 'wpinet', linkage: 'static' lib project: ':wpiutil', library: 'wpiutil', linkage: 'static' + if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(binary, 'ni_link_libraries', 'ni_runtime_libraries') + } if (binary.targetPlatform.operatingSystem.isLinux()) { linker.args "-lutil" } @@ -275,6 +281,9 @@ model { binaries.all { binary -> lib project: ':wpinet', library: 'wpinet', linkage: 'static' lib project: ':wpiutil', library: 'wpiutil', linkage: 'static' + if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(binary, 'ni_link_libraries', 'ni_runtime_libraries') + } } } } diff --git a/wpiutil/build.gradle b/wpiutil/build.gradle index fa3be0ebb2..964dcf57e9 100644 --- a/wpiutil/build.gradle +++ b/wpiutil/build.gradle @@ -138,6 +138,12 @@ ext { } } } + + exeSplitSetup = { + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } + } } def examplesMap = [:]; @@ -231,6 +237,9 @@ model { targetBuildTypes 'debug' binaries.all { lib library: 'wpiutil', linkage: 'shared' + if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries', 'ni_runtime_libraries') + } } sources { cpp { @@ -245,6 +254,17 @@ model { } } +model { + binaries { + all { + if (!(it instanceof NativeBinarySpec)) return + if (it.component.name != 'wpiutil' && it.component.name != 'wpiutilBase') return + if (it.targetPlatform.name != nativeUtils.wpi.platforms.roborio) return + nativeUtils.useRequiredLibrary(it, 'ni_link_libraries') + } + } +} + sourceSets { printlog } diff --git a/wpiutil/src/main/native/cpp/timestamp.cpp b/wpiutil/src/main/native/cpp/timestamp.cpp index 521197f397..84f5022b13 100644 --- a/wpiutil/src/main/native/cpp/timestamp.cpp +++ b/wpiutil/src/main/native/cpp/timestamp.cpp @@ -6,6 +6,23 @@ #include +#ifdef __FRC_ROBORIO__ +#include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#include +#include +#include +#include +#pragma GCC diagnostic pop +namespace fpga { +using namespace nFPGA; +using namespace nRoboRIO_FPGANamespace; +} // namespace fpga +#include +#endif + #ifdef _WIN32 #include @@ -15,6 +32,14 @@ #include #endif +#include + +#include "fmt/format.h" + +#ifdef __FRC_ROBORIO__ +static std::unique_ptr global; +#endif + // offset in microseconds static uint64_t time_since_epoch() noexcept { #ifdef _WIN32 @@ -88,12 +113,57 @@ uint64_t wpi::NowDefault() { static std::atomic now_impl{wpi::NowDefault}; +void wpi::impl::SetupNowRio() { +#ifdef __FRC_ROBORIO__ + if (!global) { + nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass = + nLoadOut::getTargetClass(); + int32_t status = 0; + global.reset(fpga::tGlobal::create(&status)); + } +#endif +} + void wpi::SetNowImpl(uint64_t (*func)(void)) { now_impl = func ? func : NowDefault; } uint64_t wpi::Now() { +#ifdef __FRC_ROBORIO__ + // Same code as HAL_GetFPGATime() + if (!global) { + std::fputs( + "FPGA not yet configured in wpi::Now(). Time will not be correct", + stderr); + std::fflush(stderr); + return 0; + } + int32_t status = 0; + uint64_t upper1 = global->readLocalTimeUpper(&status); + uint32_t lower = global->readLocalTime(&status); + uint64_t upper2 = global->readLocalTimeUpper(&status); + if (status != 0) { + goto err; + } + if (upper1 != upper2) { + // Rolled over between the lower call, reread lower + lower = global->readLocalTime(&status); + if (status != 0) { + goto err; + } + } + return (upper2 << 32) + lower; + +err: + fmt::print(stderr, + "Call to FPGA failed in wpi::Now() with status {}. " + "Initialization might have failed. Time will not be correct\n", + status); + std::fflush(stderr); + return 0; +#else return (now_impl.load())(); +#endif } uint64_t wpi::GetSystemTime() { @@ -102,6 +172,10 @@ uint64_t wpi::GetSystemTime() { extern "C" { +void WPI_Impl_SetupNowRio(void) { + return wpi::impl::SetupNowRio(); +} + uint64_t WPI_NowDefault(void) { return wpi::NowDefault(); } diff --git a/wpiutil/src/main/native/include/wpi/timestamp.h b/wpiutil/src/main/native/include/wpi/timestamp.h index c50117ce24..3444781e94 100644 --- a/wpiutil/src/main/native/include/wpi/timestamp.h +++ b/wpiutil/src/main/native/include/wpi/timestamp.h @@ -11,6 +11,13 @@ extern "C" { #endif +/** + * Initialize the on-Rio Now() implementation to use the FPGA timestamp. + * No effect on non-Rio platforms. This is called by HAL_Initialize() and + * thus should generally not be called by user code. + */ +void WPI_Impl_SetupNowRio(void); + /** * The default implementation used for Now(). * In general this is the time returned by the operating system. @@ -48,12 +55,21 @@ uint64_t WPI_GetSystemTime(void); #ifdef __cplusplus namespace wpi { +namespace impl { +/** + * Initialize the on-Rio Now() implementation to use the FPGA timestamp. + * No effect on non-Rio platforms. This is called by HAL_Initialize() and + * thus should generally not be called by user code. + */ +void SetupNowRio(); +} // namespace impl + /** * The default implementation used for Now(). * In general this is the time returned by the operating system. * @return Time in microseconds. */ -uint64_t NowDefault(void); +uint64_t NowDefault(); /** * Set the implementation used by Now(). @@ -68,7 +84,7 @@ void SetNowImpl(uint64_t (*func)()); * This is a monotonic clock with an undefined epoch. * @return Time in microseconds. */ -uint64_t Now(void); +uint64_t Now(); /** * Return the current system time in microseconds since the Unix epoch