diff --git a/hal/include/HAL/HAL.hpp b/hal/include/HAL/HAL.hpp index f09a5d2483..75c72e38f7 100644 --- a/hal/include/HAL/HAL.hpp +++ b/hal/include/HAL/HAL.hpp @@ -222,7 +222,7 @@ extern "C" uint16_t getFPGAVersion(int32_t *status); uint32_t getFPGARevision(int32_t *status); - uint32_t getFPGATime(int32_t *status); + uint64_t getFPGATime(int32_t *status); bool getFPGAButton(int32_t *status); diff --git a/hal/include/HAL/Notifier.hpp b/hal/include/HAL/Notifier.hpp index 1ec7ec952b..e8cb3812cc 100644 --- a/hal/include/HAL/Notifier.hpp +++ b/hal/include/HAL/Notifier.hpp @@ -4,9 +4,9 @@ extern "C" { - void* initializeNotifier(void (*process)(uint32_t, void*), void* param, int32_t *status); + void* initializeNotifier(void (*process)(uint64_t, void*), void* param, int32_t *status); void cleanNotifier(void* notifier_pointer, int32_t *status); void* getNotifierParam(void* notifier_pointer, int32_t *status); - void updateNotifierAlarm(void* notifier_pointer, uint32_t triggerTime, int32_t *status); + void updateNotifierAlarm(void* notifier_pointer, uint64_t triggerTime, int32_t *status); void stopNotifierAlarm(void* notifier_pointer, int32_t *status); } diff --git a/hal/lib/Athena/Digital.cpp b/hal/lib/Athena/Digital.cpp index 0d4ff5f175..29dc8198ff 100644 --- a/hal/lib/Athena/Digital.cpp +++ b/hal/lib/Athena/Digital.cpp @@ -88,7 +88,7 @@ tSPI *spiSystem; struct SPIAccumulator { void* notifier = nullptr; - uint32_t triggerTime; + uint64_t triggerTime; uint32_t period; int64_t value = 0; @@ -1499,7 +1499,7 @@ priority_recursive_mutex& spiGetSemaphore(uint8_t port) { return spiMXPSemaphore; } -static void spiAccumulatorProcess(uint32_t currentTime, void *param) { +static void spiAccumulatorProcess(uint64_t currentTime, void *param) { SPIAccumulator* accum = (SPIAccumulator*)param; // perform SPI transaction diff --git a/hal/lib/Athena/HALAthena.cpp b/hal/lib/Athena/HALAthena.cpp index 852948ae8d..23f5266121 100644 --- a/hal/lib/Athena/HALAthena.cpp +++ b/hal/lib/Athena/HALAthena.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include // linux for kill @@ -23,6 +24,11 @@ const uint32_t kSystemClockTicksPerMicrosecond = 40; static tGlobal *global = nullptr; static tSysWatchdog *watchdog = nullptr; +static priority_mutex timeMutex; +static uint32_t timeEpoch = 0; +static uint32_t prevFPGATime = 0; +static void* rolloverNotifier = nullptr; + void* getPort(uint8_t pin) { Port* port = new Port(); @@ -184,13 +190,19 @@ uint32_t getFPGARevision(int32_t *status) * * @return The current time in microseconds according to the FPGA (since FPGA reset). */ -uint32_t getFPGATime(int32_t *status) +uint64_t getFPGATime(int32_t *status) { if (!global) { *status = NiFpga_Status_ResourceNotInitialized; return 0; } - return global->readLocalTime(status); + std::lock_guard lock(timeMutex); + uint32_t fpgaTime = global->readLocalTime(status); + if (*status != 0) return 0; + // check for rollover + if (fpgaTime < prevFPGATime) ++timeEpoch; + prevFPGATime = fpgaTime; + return (((uint64_t)timeEpoch) << 32) | ((uint64_t)fpgaTime); } /** @@ -235,6 +247,12 @@ static void HALCleanupAtExit() { watchdog = nullptr; } +static void timerRollover(uint64_t currentTime, void*) { + // reschedule timer for next rollover + int32_t status = 0; + updateNotifierAlarm(rolloverNotifier, currentTime + 0x80000000ULL, &status); +} + /** * Call this to start up HAL. This is required for robot programs. */ @@ -256,6 +274,14 @@ int HALInitialize(int mode) std::atexit(HALCleanupAtExit); + if (!rolloverNotifier) + rolloverNotifier = initializeNotifier(timerRollover, nullptr, &status); + if (status == 0) { + uint64_t curTime = getFPGATime(&status); + if (status == 0) + updateNotifierAlarm(rolloverNotifier, curTime + 0x80000000ULL, &status); + } + // Kill any previous robot programs std::fstream fs; // By making this both in/out, it won't give us an error if it doesnt exist @@ -302,6 +328,7 @@ int HALInitialize(int mode) pid = getpid(); fs << pid << std::endl; fs.close(); + return 1; } diff --git a/hal/lib/Athena/Notifier.cpp b/hal/lib/Athena/Notifier.cpp index f7f69c3d02..09337f917c 100644 --- a/hal/lib/Athena/Notifier.cpp +++ b/hal/lib/Athena/Notifier.cpp @@ -12,12 +12,12 @@ static priority_mutex notifierInterruptMutex; static priority_recursive_mutex notifierMutex; static tAlarm *notifierAlarm = nullptr; static tInterruptManager *notifierManager = nullptr; -static uint32_t closestTrigger = UINT32_MAX; +static uint64_t closestTrigger = UINT64_MAX; struct Notifier { Notifier *prev, *next; void *param; - void (*process)(uint32_t, void*); - uint32_t triggerTime = UINT32_MAX; + void (*process)(uint64_t, void*); + uint64_t triggerTime = UINT64_MAX; }; static Notifier *notifiers = nullptr; static std::atomic_flag notifierAtexitRegistered = ATOMIC_FLAG_INIT; @@ -28,19 +28,19 @@ static void alarmCallback(uint32_t, void*) std::unique_lock sync(notifierMutex); int32_t status = 0; - uint32_t currentTime = 0; + uint64_t currentTime = 0; // the hardware disables itself after each alarm - closestTrigger = UINT32_MAX; + closestTrigger = UINT64_MAX; // process all notifiers Notifier *notifier = notifiers; while (notifier) { - if (notifier->triggerTime != UINT32_MAX) { + if (notifier->triggerTime != UINT64_MAX) { if (currentTime == 0) currentTime = getFPGATime(&status); if (notifier->triggerTime < currentTime) { - notifier->triggerTime = UINT32_MAX; + notifier->triggerTime = UINT64_MAX; auto process = notifier->process; auto param = notifier->param; sync.unlock(); @@ -59,7 +59,7 @@ static void cleanupNotifierAtExit() { notifierManager = nullptr; } -void* initializeNotifier(void (*process)(uint32_t, void*), void *param, int32_t *status) +void* initializeNotifier(void (*process)(uint64_t, void*), void *param, int32_t *status) { if (!process) { *status = NULL_PARAMETER; @@ -124,22 +124,23 @@ void* getNotifierParam(void* notifier_pointer, int32_t *status) return ((Notifier*)notifier_pointer)->param; } -void updateNotifierAlarm(void* notifier_pointer, uint32_t triggerTime, int32_t *status) +void updateNotifierAlarm(void* notifier_pointer, uint64_t triggerTime, int32_t *status) { std::lock_guard sync(notifierMutex); Notifier* notifier = (Notifier*)notifier_pointer; notifier->triggerTime = triggerTime; - bool wasActive = (closestTrigger != UINT32_MAX); + bool wasActive = (closestTrigger != UINT64_MAX); - if (!notifierInterruptMutex.try_lock() || notifierRefCount == 0 || - !notifierAlarm) - return; + if (!notifierInterruptMutex.try_lock() || notifierRefCount == 0 || + !notifierAlarm) + return; - // Update alarm time if closer than current. + // Update alarm time if closer than current. if (triggerTime < closestTrigger) { closestTrigger = triggerTime; - notifierAlarm->writeTriggerTime(triggerTime, status); + // Simply truncate the hardware trigger time to 32-bit. + notifierAlarm->writeTriggerTime((uint32_t)triggerTime, status); } // Enable the alarm. The hardware disables itself after each alarm. if (!wasActive) notifierAlarm->writeEnable(true, status); @@ -151,5 +152,5 @@ void stopNotifierAlarm(void* notifier_pointer, int32_t *status) { std::lock_guard sync(notifierMutex); Notifier* notifier = (Notifier*)notifier_pointer; - notifier->triggerTime = UINT32_MAX; + notifier->triggerTime = UINT64_MAX; } diff --git a/wpilibc/Athena/include/Notifier.h b/wpilibc/Athena/include/Notifier.h index ce887667a1..7fe758f611 100644 --- a/wpilibc/Athena/include/Notifier.h +++ b/wpilibc/Athena/include/Notifier.h @@ -35,7 +35,7 @@ class Notifier : public ErrorBase { // update the HAL alarm void UpdateAlarm(); // HAL callback - static void Notify(uint32_t currentTimeInt, void *param); + static void Notify(uint64_t currentTimeInt, void *param); // held while updating process information priority_mutex m_processMutex; diff --git a/wpilibc/Athena/src/Notifier.cpp b/wpilibc/Athena/src/Notifier.cpp index 80667edd27..5dffc9f005 100644 --- a/wpilibc/Athena/src/Notifier.cpp +++ b/wpilibc/Athena/src/Notifier.cpp @@ -43,7 +43,7 @@ Notifier::~Notifier() { */ void Notifier::UpdateAlarm() { int32_t status = 0; - updateNotifierAlarm(m_notifier, (uint32_t)(m_expirationTime * 1e6), &status); + updateNotifierAlarm(m_notifier, (uint64_t)(m_expirationTime * 1e6), &status); wpi_setErrorWithContext(status, getHALErrorMessage(status)); } @@ -51,7 +51,7 @@ void Notifier::UpdateAlarm() { * Notify is called by the HAL layer. We simply need to pass it through to * the user handler. */ -void Notifier::Notify(uint32_t currentTimeInt, void *param) { +void Notifier::Notify(uint64_t currentTimeInt, void *param) { Notifier* notifier = static_cast(param); notifier->m_processMutex.lock(); diff --git a/wpilibc/Athena/src/Utility.cpp b/wpilibc/Athena/src/Utility.cpp index 5998f0f939..75de176e18 100644 --- a/wpilibc/Athena/src/Utility.cpp +++ b/wpilibc/Athena/src/Utility.cpp @@ -156,9 +156,9 @@ uint32_t GetFPGARevision() { * @return The current time in microseconds according to the FPGA (since FPGA * reset). */ -uint32_t GetFPGATime() { +uint64_t GetFPGATime() { int32_t status = 0; - uint32_t time = getFPGATime(&status); + uint64_t time = getFPGATime(&status); wpi_setGlobalErrorWithContext(status, getHALErrorMessage(status)); return time; } diff --git a/wpilibc/shared/include/Utility.h b/wpilibc/shared/include/Utility.h index 69edb6343b..6a0fae0f05 100644 --- a/wpilibc/shared/include/Utility.h +++ b/wpilibc/shared/include/Utility.h @@ -46,6 +46,6 @@ void wpi_suspendOnAssertEnabled(bool enabled); uint16_t GetFPGAVersion(); uint32_t GetFPGARevision(); -uint32_t GetFPGATime(); +uint64_t GetFPGATime(); bool GetUserButton(); std::string GetStackTrace(uint32_t offset); diff --git a/wpilibc/simulation/src/Utility.cpp b/wpilibc/simulation/src/Utility.cpp index 7d12eb85c1..e4f9b47f4f 100644 --- a/wpilibc/simulation/src/Utility.cpp +++ b/wpilibc/simulation/src/Utility.cpp @@ -159,7 +159,7 @@ bool wpi_assertNotEqual_impl(int valueA, * * @return The current time in microseconds according to the FPGA (since FPGA reset). */ -uint32_t GetFPGATime() +uint64_t GetFPGATime() { return wpilib::internal::simTime * 1e6; } diff --git a/wpilibj/src/athena/cpp/lib/NotifierJNI.cpp b/wpilibj/src/athena/cpp/lib/NotifierJNI.cpp index 34c73aa853..830472fe77 100644 --- a/wpilibj/src/athena/cpp/lib/NotifierJNI.cpp +++ b/wpilibj/src/athena/cpp/lib/NotifierJNI.cpp @@ -38,14 +38,14 @@ class NotifierThreadJNI : public SafeThread { bool m_notify = false; jobject m_func = nullptr; jmethodID m_mid; - uint32_t m_currentTime; + uint64_t m_currentTime; }; class NotifierJNI : public SafeThreadOwner { public: void SetFunc(JNIEnv* env, jobject func, jmethodID mid); - void Notify(uint32_t currentTime) { + void Notify(uint64_t currentTime) { auto thr = GetThread(); if (!thr) return; thr->m_currentTime = currentTime; @@ -81,9 +81,9 @@ void NotifierThreadJNI::Main() { if (!m_func) continue; jobject func = m_func; jmethodID mid = m_mid; - uint32_t currentTime = m_currentTime; + uint64_t currentTime = m_currentTime; lock.unlock(); // don't hold mutex during callback execution - env->CallVoidMethod(func, mid, (jint)currentTime); + env->CallVoidMethod(func, mid, (jlong)currentTime); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); @@ -97,7 +97,7 @@ void NotifierThreadJNI::Main() { jvm->DetachCurrentThread(); } -void notifierHandler(uint32_t currentTimeInt, void* param) { +void notifierHandler(uint64_t currentTimeInt, void* param) { ((NotifierJNI*)param)->Notify(currentTimeInt); } @@ -119,7 +119,7 @@ JNIEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_NotifierJNI_initializeNot assert(false); return 0; } - jmethodID mid = env->GetMethodID(cls, "apply", "(I)V"); + jmethodID mid = env->GetMethodID(cls, "apply", "(J)V"); if (mid == 0) { NOTIFIERJNI_LOG(logERROR) << "Error getting java method ID"; assert(false); @@ -169,10 +169,10 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_NotifierJNI_cleanNotifier /* * Class: edu_wpi_first_wpilibj_hal_NotifierJNI * Method: updateNotifierAlarm - * Signature: (JI)V + * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_NotifierJNI_updateNotifierAlarm - (JNIEnv *env, jclass cls, jlong notifierPtr, jint triggerTime) + (JNIEnv *env, jclass cls, jlong notifierPtr, jlong triggerTime) { NOTIFIERJNI_LOG(logDEBUG) << "Calling NOTIFIERJNI updateNotifierAlarm"; @@ -181,7 +181,7 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_NotifierJNI_updateNotifier NOTIFIERJNI_LOG(logDEBUG) << "triggerTime = " << triggerTime; int32_t status = 0; - updateNotifierAlarm((void*)notifierPtr, (uint32_t)triggerTime, &status); + updateNotifierAlarm((void*)notifierPtr, (uint64_t)triggerTime, &status); NOTIFIERJNI_LOG(logDEBUG) << "Status = " << status; CheckStatus(env, status); } diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/Notifier.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/Notifier.java index 502fb2727e..70fc81a4d7 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/Notifier.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/Notifier.java @@ -48,7 +48,7 @@ public class Notifier { * Update the alarm hardware to reflect the next alarm. */ private void updateAlarm() { - NotifierJNI.updateNotifierAlarm(m_notifier, (int) (m_expirationTime * 1e6)); + NotifierJNI.updateNotifierAlarm(m_notifier, (long) (m_expirationTime * 1e6)); } /** @@ -56,7 +56,7 @@ public class Notifier { * calling of the user handler. */ @Override - public void apply(int time) { + public void apply(long time) { m_processLock.lock(); if (m_periodic) { m_expirationTime += m_period; diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/hal/NotifierJNI.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/hal/NotifierJNI.java index f3c3df2046..8df33b96a2 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/hal/NotifierJNI.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/hal/NotifierJNI.java @@ -14,7 +14,7 @@ public class NotifierJNI extends JNIWrapper { * Callback function */ public interface NotifierJNIHandlerFunction { - void apply(int curTime); + void apply(long curTime); } /** @@ -30,7 +30,7 @@ public class NotifierJNI extends JNIWrapper { /** * Sets the notifier to call the callback in another triggerTime microseconds. */ - public static native void updateNotifierAlarm(long notifierPtr, int triggerTime); + public static native void updateNotifierAlarm(long notifierPtr, long triggerTime); /** * Tells the notifier to stop calling the callback.