From ad53fb19b4478f0c97aaf596769f9a43338758d0 Mon Sep 17 00:00:00 2001 From: Thad House Date: Mon, 24 Oct 2022 18:26:07 -0700 Subject: [PATCH] [hal] Use new HMB api for addressable LED (#4479) Theres is now a built in HMB api, but you have to dlopen it to access it. Moved our existing infrastructure for this to its own class, added the new functions, then updated interrupts and LEDs to use it. --- hal/src/main/native/athena/AddressableLED.cpp | 59 ++++------------- hal/src/main/native/athena/FPGACalls.cpp | 66 +++++++++++++++++++ hal/src/main/native/athena/FPGACalls.h | 46 +++++++++++++ hal/src/main/native/athena/HAL.cpp | 12 ++-- .../main/native/athena/InterruptManager.cpp | 55 +--------------- .../include/hal/roborio/InterruptManager.h | 2 +- 6 files changed, 133 insertions(+), 107 deletions(-) create mode 100644 hal/src/main/native/athena/FPGACalls.cpp create mode 100644 hal/src/main/native/athena/FPGACalls.h diff --git a/hal/src/main/native/athena/AddressableLED.cpp b/hal/src/main/native/athena/AddressableLED.cpp index ba446901e5..5e55c93e14 100644 --- a/hal/src/main/native/athena/AddressableLED.cpp +++ b/hal/src/main/native/athena/AddressableLED.cpp @@ -6,11 +6,11 @@ #include -#include #include #include "ConstantsInternal.h" #include "DigitalInternal.h" +#include "FPGACalls.h" #include "HALInitializer.h" #include "HALInternal.h" #include "PortsInternal.h" @@ -21,51 +21,6 @@ using namespace hal; -extern "C" { -NiFpga_Status NiFpga_ClientFunctionCall(NiFpga_Session session, uint32_t group, - uint32_t functionId, - const void* inBuffer, - size_t inBufferSize, void* outBuffer, - size_t outBufferSize); -} // extern "C" - -// Shim for broken ChipObject function -static const uint32_t clientFeature_hostMemoryBuffer = 0; -static const uint32_t hostMemoryBufferFunction_open = 2; - -// Input arguments for HMB open -struct AtomicHMBOpenInputs { - const char* memoryName; -}; - -// Output arguments for HMB open -struct AtomicHMBOpenOutputs { - size_t size; - void* virtualAddress; -}; - -static NiFpga_Status OpenHostMemoryBuffer(NiFpga_Session session, - const char* memoryName, - void** virtualAddress, size_t* size) { - struct AtomicHMBOpenOutputs outputs; - - struct AtomicHMBOpenInputs inputs; - inputs.memoryName = memoryName; - - NiFpga_Status retval = NiFpga_ClientFunctionCall( - session, clientFeature_hostMemoryBuffer, hostMemoryBufferFunction_open, - &inputs, sizeof(struct AtomicHMBOpenInputs), &outputs, - sizeof(struct AtomicHMBOpenOutputs)); - if (NiFpga_IsError(retval)) { - return retval; - } - *virtualAddress = outputs.virtualAddress; - if (size) { - *size = outputs.size; - } - return retval; -} - namespace { struct AddressableLED { std::unique_ptr led; @@ -89,6 +44,8 @@ void InitializeAddressableLED() { } } // namespace hal::init +static constexpr const char* HmbName = "HMB_0_LED"; + extern "C" { HAL_AddressableLEDHandle HAL_InitializeAddressableLED( @@ -146,8 +103,8 @@ HAL_AddressableLEDHandle HAL_InitializeAddressableLED( uint32_t session = led->led->getSystemInterface()->getHandle(); - *status = OpenHostMemoryBuffer(session, "HMB_0_LED", &led->ledBuffer, - &led->ledBufferSize); + *status = hal::HAL_NiFpga_OpenHmb(session, HmbName, &led->ledBufferSize, + &led->ledBuffer); if (*status != 0) { addressableLEDHandles->Free(handle); @@ -158,6 +115,12 @@ HAL_AddressableLEDHandle HAL_InitializeAddressableLED( } void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) { + auto led = addressableLEDHandles->Get(handle); + if (!led) { + return; + } + uint32_t session = led->led->getSystemInterface()->getHandle(); + hal::HAL_NiFpga_CloseHmb(session, HmbName); addressableLEDHandles->Free(handle); } diff --git a/hal/src/main/native/athena/FPGACalls.cpp b/hal/src/main/native/athena/FPGACalls.cpp new file mode 100644 index 0000000000..0b04019b1d --- /dev/null +++ b/hal/src/main/native/athena/FPGACalls.cpp @@ -0,0 +1,66 @@ +// 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 "FPGACalls.h" + +#include + +#include "dlfcn.h" +#include "hal/Errors.h" + +static void* NiFpgaLibrary = nullptr; + +namespace hal { +HAL_NiFpga_ReserveIrqContextFunc HAL_NiFpga_ReserveIrqContext; +HAL_NiFpga_UnreserveIrqContextFunc HAL_NiFpga_UnreserveIrqContext; +HAL_NiFpga_WaitOnIrqsFunc HAL_NiFpga_WaitOnIrqs; +HAL_NiFpga_AcknowledgeIrqsFunc HAL_NiFpga_AcknowledgeIrqs; +HAL_NiFpga_OpenHmbFunc HAL_NiFpga_OpenHmb; +HAL_NiFpga_CloseHmbFunc HAL_NiFpga_CloseHmb; + +namespace init { +int InitializeFPGA() { + NiFpgaLibrary = dlopen("libNiFpga.so", RTLD_LAZY); + if (!NiFpgaLibrary) { + return errno; + } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" + HAL_NiFpga_ReserveIrqContext = + reinterpret_cast( + dlsym(NiFpgaLibrary, "NiFpgaDll_ReserveIrqContext")); + HAL_NiFpga_UnreserveIrqContext = + reinterpret_cast( + dlsym(NiFpgaLibrary, "NiFpgaDll_UnreserveIrqContext")); + HAL_NiFpga_WaitOnIrqs = reinterpret_cast( + dlsym(NiFpgaLibrary, "NiFpgaDll_WaitOnIrqs")); + HAL_NiFpga_AcknowledgeIrqs = reinterpret_cast( + dlsym(NiFpgaLibrary, "NiFpgaDll_AcknowledgeIrqs")); + HAL_NiFpga_OpenHmb = reinterpret_cast( + dlsym(NiFpgaLibrary, "NiFpgaDll_OpenHmb")); + HAL_NiFpga_CloseHmb = reinterpret_cast( + dlsym(NiFpgaLibrary, "NiFpgaDll_CloseHmb")); +#pragma GCC diagnostic pop + + if (HAL_NiFpga_ReserveIrqContext == nullptr || + HAL_NiFpga_UnreserveIrqContext == nullptr || + HAL_NiFpga_WaitOnIrqs == nullptr || + HAL_NiFpga_AcknowledgeIrqs == nullptr || HAL_NiFpga_OpenHmb == nullptr || + HAL_NiFpga_CloseHmb == nullptr) { + HAL_NiFpga_ReserveIrqContext = nullptr; + HAL_NiFpga_UnreserveIrqContext = nullptr; + HAL_NiFpga_WaitOnIrqs = nullptr; + HAL_NiFpga_AcknowledgeIrqs = nullptr; + HAL_NiFpga_OpenHmb = nullptr; + HAL_NiFpga_CloseHmb = nullptr; + dlclose(NiFpgaLibrary); + NiFpgaLibrary = nullptr; + return NO_AVAILABLE_RESOURCES; + } + + return HAL_SUCCESS; +} +} // namespace init +} // namespace hal diff --git a/hal/src/main/native/athena/FPGACalls.h b/hal/src/main/native/athena/FPGACalls.h new file mode 100644 index 0000000000..46e8ac407c --- /dev/null +++ b/hal/src/main/native/athena/FPGACalls.h @@ -0,0 +1,46 @@ +// 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. + +#pragma once + +#include + +namespace hal { +namespace init { +[[nodiscard]] int InitializeFPGA(); +} // namespace init + +using HAL_NiFpga_ReserveIrqContextFunc = + NiFpga_Status (*)(NiFpga_Session session, NiFpga_IrqContext* context); + +extern HAL_NiFpga_ReserveIrqContextFunc HAL_NiFpga_ReserveIrqContext; + +using HAL_NiFpga_UnreserveIrqContextFunc = + NiFpga_Status (*)(NiFpga_Session session, NiFpga_IrqContext context); + +extern HAL_NiFpga_UnreserveIrqContextFunc HAL_NiFpga_UnreserveIrqContext; + +using HAL_NiFpga_WaitOnIrqsFunc = NiFpga_Status (*)( + NiFpga_Session session, NiFpga_IrqContext context, uint32_t irqs, + uint32_t timeout, uint32_t* irqsAsserted, NiFpga_Bool* timedOut); + +extern HAL_NiFpga_WaitOnIrqsFunc HAL_NiFpga_WaitOnIrqs; + +using HAL_NiFpga_AcknowledgeIrqsFunc = NiFpga_Status (*)(NiFpga_Session session, + uint32_t irqs); + +extern HAL_NiFpga_AcknowledgeIrqsFunc HAL_NiFpga_AcknowledgeIrqs; + +using HAL_NiFpga_OpenHmbFunc = NiFpga_Status (*)(const NiFpga_Session session, + const char* memoryName, + size_t* memorySize, + void** virtualAddress); + +extern HAL_NiFpga_OpenHmbFunc HAL_NiFpga_OpenHmb; + +using HAL_NiFpga_CloseHmbFunc = NiFpga_Status (*)(const NiFpga_Session session, + const char* memoryName); + +extern HAL_NiFpga_CloseHmbFunc HAL_NiFpga_CloseHmb; +} // namespace hal diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp index 08abf14bb6..6fd045903f 100644 --- a/hal/src/main/native/athena/HAL.cpp +++ b/hal/src/main/native/athena/HAL.cpp @@ -21,6 +21,7 @@ #include #include +#include "FPGACalls.h" #include "HALInitializer.h" #include "HALInternal.h" #include "hal/ChipObject.h" @@ -394,6 +395,11 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) { return true; } + int fpgaInit = hal::init::InitializeFPGA(); + if (fpgaInit != HAL_SUCCESS) { + return false; + } + hal::init::InitializeHAL(); hal::init::HAL_IsInitialized.store(true); @@ -426,11 +432,7 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) { return false; } - status = InterruptManager::Initialize(global->getSystemInterface()); - - if (status != 0) { - return false; - } + InterruptManager::Initialize(global->getSystemInterface()); hal::InitializeDriverStation(); diff --git a/hal/src/main/native/athena/InterruptManager.cpp b/hal/src/main/native/athena/InterruptManager.cpp index 0bd0672ad5..420f8065c8 100644 --- a/hal/src/main/native/athena/InterruptManager.cpp +++ b/hal/src/main/native/athena/InterruptManager.cpp @@ -6,34 +6,11 @@ #include +#include "FPGACalls.h" #include "HALInternal.h" #include "dlfcn.h" #include "hal/Errors.h" -// Low level FPGA calls -using HAL_NiFpga_ReserveIrqContextFunc = - NiFpga_Status (*)(NiFpga_Session session, NiFpga_IrqContext* context); - -static HAL_NiFpga_ReserveIrqContextFunc HAL_NiFpga_ReserveIrqContext; - -using HAL_NiFpga_UnreserveIrqContextFunc = - NiFpga_Status (*)(NiFpga_Session session, NiFpga_IrqContext context); - -static HAL_NiFpga_UnreserveIrqContextFunc HAL_NiFpga_UnreserveIrqContext; - -using HAL_NiFpga_WaitOnIrqsFunc = NiFpga_Status (*)( - NiFpga_Session session, NiFpga_IrqContext context, uint32_t irqs, - uint32_t timeout, uint32_t* irqsAsserted, NiFpga_Bool* timedOut); - -static HAL_NiFpga_WaitOnIrqsFunc HAL_NiFpga_WaitOnIrqs; - -using HAL_NiFpga_AcknowledgeIrqsFunc = NiFpga_Status (*)(NiFpga_Session session, - uint32_t irqs); - -static HAL_NiFpga_AcknowledgeIrqsFunc HAL_NiFpga_AcknowledgeIrqs; - -static void* NiFpgaLibrary = nullptr; - using namespace hal; InterruptManager& InterruptManager::GetInstance() { @@ -41,37 +18,9 @@ InterruptManager& InterruptManager::GetInstance() { return manager; } -int32_t InterruptManager::Initialize(tSystemInterface* baseSystem) { +void InterruptManager::Initialize(tSystemInterface* baseSystem) { auto& manager = GetInstance(); manager.fpgaSession = baseSystem->getHandle(); - - NiFpgaLibrary = dlopen("libNiFpga.so", RTLD_LAZY); - if (!NiFpgaLibrary) { - return errno; - } - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - HAL_NiFpga_ReserveIrqContext = - reinterpret_cast( - dlsym(NiFpgaLibrary, "NiFpgaDll_ReserveIrqContext")); - HAL_NiFpga_UnreserveIrqContext = - reinterpret_cast( - dlsym(NiFpgaLibrary, "NiFpgaDll_UnreserveIrqContext")); - HAL_NiFpga_WaitOnIrqs = reinterpret_cast( - dlsym(NiFpgaLibrary, "NiFpgaDll_WaitOnIrqs")); - HAL_NiFpga_AcknowledgeIrqs = reinterpret_cast( - dlsym(NiFpgaLibrary, "NiFpgaDll_AcknowledgeIrqs")); -#pragma GCC diagnostic pop - - if (HAL_NiFpga_ReserveIrqContext == nullptr || - HAL_NiFpga_UnreserveIrqContext == nullptr || - HAL_NiFpga_WaitOnIrqs == nullptr || - HAL_NiFpga_AcknowledgeIrqs == nullptr) { - return NO_AVAILABLE_RESOURCES; - } - - return HAL_SUCCESS; } NiFpga_IrqContext InterruptManager::GetContext() noexcept { diff --git a/hal/src/main/native/include/hal/roborio/InterruptManager.h b/hal/src/main/native/include/hal/roborio/InterruptManager.h index ee7fc38c43..36d904b49e 100644 --- a/hal/src/main/native/include/hal/roborio/InterruptManager.h +++ b/hal/src/main/native/include/hal/roborio/InterruptManager.h @@ -14,7 +14,7 @@ namespace hal { class InterruptManager { public: static InterruptManager& GetInstance(); - static int32_t Initialize(tSystemInterface* baseSystem); + static void Initialize(tSystemInterface* baseSystem); NiFpga_IrqContext GetContext() noexcept; void ReleaseContext(NiFpga_IrqContext context) noexcept;