mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpiutil] timestamp: Call FPGA functions directly (#5235)
This works around an exit race with wpi::Now() on Rio; it was overridden to call HAL_GetFPGATime(), which calls chipobject, but on exit, because there was not a library dependency, the chipobject could be destroyed prior to wpiutil/wpinet being shut down.
This commit is contained in:
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/Synchronization.h>
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -6,6 +6,23 @@
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#ifdef __FRC_ROBORIO__
|
||||
#include <stdint.h>
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
#include <FRC_FPGA_ChipObject/RoboRIO_FRC_ChipObject_Aliases.h>
|
||||
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/nInterfaceGlobals.h>
|
||||
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tGlobal.h>
|
||||
#include <FRC_NetworkCommunication/LoadOut.h>
|
||||
#pragma GCC diagnostic pop
|
||||
namespace fpga {
|
||||
using namespace nFPGA;
|
||||
using namespace nRoboRIO_FPGANamespace;
|
||||
} // namespace fpga
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
@@ -15,6 +32,14 @@
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#ifdef __FRC_ROBORIO__
|
||||
static std::unique_ptr<fpga::tGlobal> 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<uint64_t (*)()> 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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user