From b0db842c535c3a01eb9f679db46de9a4457c328c Mon Sep 17 00:00:00 2001 From: Ryan Blue Date: Wed, 16 Oct 2024 10:40:03 -0400 Subject: [PATCH] Refactor athena initialization to use handles Each port gets its own init method to streamline the main codepath --- hal/src/main/native/athena/SPI.cpp | 302 +++++++++++++----------- hal/src/main/native/include/hal/SPI.h | 2 +- hal/src/main/native/include/hal/Types.h | 2 + hal/src/main/native/sim/SPI.cpp | 4 +- 4 files changed, 172 insertions(+), 138 deletions(-) diff --git a/hal/src/main/native/athena/SPI.cpp b/hal/src/main/native/athena/SPI.cpp index d77f81ec7bb..03777ce9d87 100644 --- a/hal/src/main/native/athena/SPI.cpp +++ b/hal/src/main/native/athena/SPI.cpp @@ -31,6 +31,7 @@ using namespace hal; namespace { struct SPI { + HAL_SPIPort port; int32_t nativeHandle; wpi::mutex handleMutex; wpi::mutex apiMutex; @@ -44,7 +45,7 @@ static constexpr int32_t kSpiMaxHandles = 5; /// Hacky hacky bad, should probably switch HAL api to use handles instead of /// this class SPIHandleResource - : public IndexedHandleResource { public: HAL_Handle GetHandleForPort(HAL_SPIPort port) { @@ -84,8 +85,6 @@ void InitializeSPI() { } } // namespace hal::init -extern "C" { - static void CommonSPIPortInit(int32_t* status) { // All false cases will set if (spiPortCount.fetch_add(1) == 0) { @@ -120,14 +119,161 @@ static void CommonSPIPortFree(void) { } } -void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { +static int InitOnboardCS0(int32_t* status) { + CommonSPIPortInit(status); + if (*status != 0) { + *status = INCOMPATIBLE_STATE; + return -1; + } + // CS0 is not a DIO port, so nothing to allocate + int handle = open("/dev/spidev0.0", O_RDWR); + if (handle < 0) { + wpi::print("Failed to open SPI port {}: {}\n", + static_cast(HAL_SPI_kOnboardCS0), std::strerror(errno)); + CommonSPIPortFree(); + *status = INCOMPATIBLE_STATE; + return -1; + } + return handle; +} + +static int InitOnboardCS1(int32_t* status) { + CommonSPIPortInit(status); + if (*status != 0) { + return -1; + } + // CS1, Allocate + if ((digitalHandles[0] = HAL_InitializeDIOPort(createPortHandleForSPI(26), + false, nullptr, status)) == + HAL_kInvalidHandle) { + std::puts("Failed to allocate DIO 26 (CS1)"); + CommonSPIPortFree(); + *status = INCOMPATIBLE_STATE; + return -1; + } + int handle = open("/dev/spidev0.1", O_RDWR); + if (handle < 0) { + wpi::print("Failed to open SPI port {}: {}\n", + static_cast(HAL_SPI_kOnboardCS1), std::strerror(errno)); + CommonSPIPortFree(); + HAL_FreeDIOPort(digitalHandles[0]); + *status = INCOMPATIBLE_STATE; + return -1; + } + return handle; +} + +static int InitOnboardCS2(int32_t* status) { + CommonSPIPortInit(status); + if (*status != 0) { + return -1; + } + // CS2, Allocate + if ((digitalHandles[1] = HAL_InitializeDIOPort(createPortHandleForSPI(27), + false, nullptr, status)) == + HAL_kInvalidHandle) { + std::puts("Failed to allocate DIO 27 (CS2)"); + CommonSPIPortFree(); + return -1; + } + int handle = open("/dev/spidev0.2", O_RDWR); + if (handle < 0) { + wpi::print("Failed to open SPI port {}: {}\n", + static_cast(HAL_SPI_kOnboardCS2), std::strerror(errno)); + CommonSPIPortFree(); + HAL_FreeDIOPort(digitalHandles[1]); + *status = INCOMPATIBLE_STATE; + return -1; + } + return handle; +} + +static int InitOnboardCS3(int32_t* status) { + CommonSPIPortInit(status); + if (*status != 0) { + return -1; + } + // CS3, Allocate + if ((digitalHandles[2] = HAL_InitializeDIOPort(createPortHandleForSPI(28), + false, nullptr, status)) == + HAL_kInvalidHandle) { + std::puts("Failed to allocate DIO 28 (CS3)"); + CommonSPIPortFree(); + return -1; + } + int handle = open("/dev/spidev0.3", O_RDWR); + if (handle < 0) { + wpi::print("Failed to open SPI port {}: {}\n", + static_cast(HAL_SPI_kOnboardCS3), std::strerror(errno)); + CommonSPIPortFree(); + HAL_FreeDIOPort(digitalHandles[2]); + *status = INCOMPATIBLE_STATE; + return -1; + } + return handle; +} + +static int InitMXP(int32_t* status) { + initializeDigital(status); + if (*status != 0) { + return -1; + } + if ((digitalHandles[5] = HAL_InitializeDIOPort(createPortHandleForSPI(14), + false, nullptr, status)) == + HAL_kInvalidHandle) { + std::puts("Failed to allocate DIO 14"); + return -1; + } + if ((digitalHandles[6] = HAL_InitializeDIOPort(createPortHandleForSPI(15), + false, nullptr, status)) == + HAL_kInvalidHandle) { + std::puts("Failed to allocate DIO 15"); + HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated + return -1; + } + if ((digitalHandles[7] = HAL_InitializeDIOPort(createPortHandleForSPI(16), + false, nullptr, status)) == + HAL_kInvalidHandle) { + std::puts("Failed to allocate DIO 16"); + HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated + HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated + return -1; + } + if ((digitalHandles[8] = HAL_InitializeDIOPort(createPortHandleForSPI(17), + false, nullptr, status)) == + HAL_kInvalidHandle) { + std::puts("Failed to allocate DIO 17"); + HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated + HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated + HAL_FreeDIOPort(digitalHandles[7]); // free the third port allocated + return -1; + } + digitalSystem->writeEnableMXPSpecialFunction( + digitalSystem->readEnableMXPSpecialFunction(status) | 0x00F0, status); + int handle = open("/dev/spidev1.0", O_RDWR); + if (handle < 0) { + wpi::print("Failed to open SPI port {}: {}\n", + static_cast(HAL_SPI_kMXP), std::strerror(errno)); + HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated + HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated + HAL_FreeDIOPort(digitalHandles[7]); // free the third port allocated + HAL_FreeDIOPort(digitalHandles[8]); // free the fourth port allocated + *status = INCOMPATIBLE_STATE; + return -1; + } + return handle; +} + +extern "C" { + +HAL_SPIHandle HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { hal::init::CheckInit(); if (port < 0 || port >= kSpiMaxHandles) { *status = PARAMETER_OUT_OF_RANGE; hal::SetLastError( status, fmt::format("SPI port must be between 0 and {}. Requested {}", kSpiMaxHandles, static_cast(port))); - return; + return HAL_kInvalidHandle; } HAL_Handle hal_handle; @@ -136,157 +282,41 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { if (status != 0) { *status = RESOURCE_IS_ALLOCATED; // todo: previous allocation; - return; + return HAL_kInvalidHandle; } + int nativeHandle; switch (port) { case HAL_SPI_kOnboardCS0: - CommonSPIPortInit(status); - if (*status != 0) { - return; - } - // CS0 is not a DIO port, so nothing to allocate - spi->nativeHandle = open("/dev/spidev0.0", O_RDWR); - if (spi->nativeHandle < 0) { - wpi::print("Failed to open SPI port {}: {}\n", - static_cast(port), std::strerror(errno)); - CommonSPIPortFree(); - spiHandles->Free(hal_handle); - *status = INCOMPATIBLE_STATE; - return; - } + nativeHandle = InitOnboardCS0(status); break; case HAL_SPI_kOnboardCS1: - CommonSPIPortInit(status); - if (*status != 0) { - return; - } - // CS1, Allocate - if ((digitalHandles[0] = HAL_InitializeDIOPort(createPortHandleForSPI(26), - false, nullptr, status)) == - HAL_kInvalidHandle) { - std::puts("Failed to allocate DIO 26 (CS1)"); - CommonSPIPortFree(); - spiHandles->Free(hal_handle); - *status = INCOMPATIBLE_STATE; - return; - } - spi->nativeHandle = open("/dev/spidev0.1", O_RDWR); - if (spi->nativeHandle < 0) { - wpi::print("Failed to open SPI port {}: {}\n", - static_cast(port), std::strerror(errno)); - CommonSPIPortFree(); - HAL_FreeDIOPort(digitalHandles[0]); - spiHandles->Free(hal_handle); - *status = INCOMPATIBLE_STATE; - return; - } + nativeHandle = InitOnboardCS1(status); break; case HAL_SPI_kOnboardCS2: - CommonSPIPortInit(status); - if (*status != 0) { - return; - } - // CS2, Allocate - if ((digitalHandles[1] = HAL_InitializeDIOPort(createPortHandleForSPI(27), - false, nullptr, status)) == - HAL_kInvalidHandle) { - std::puts("Failed to allocate DIO 27 (CS2)"); - CommonSPIPortFree(); - return; - } - spi->nativeHandle = open("/dev/spidev0.2", O_RDWR); - if (spi->nativeHandle < 0) { - wpi::print("Failed to open SPI port {}: {}\n", - static_cast(port), std::strerror(errno)); - CommonSPIPortFree(); - HAL_FreeDIOPort(digitalHandles[1]); - spiHandles->Free(hal_handle); - *status = INCOMPATIBLE_STATE; - return; - } + nativeHandle = InitOnboardCS2(status); break; case HAL_SPI_kOnboardCS3: - CommonSPIPortInit(status); - if (*status != 0) { - return; - } - // CS3, Allocate - if ((digitalHandles[2] = HAL_InitializeDIOPort(createPortHandleForSPI(28), - false, nullptr, status)) == - HAL_kInvalidHandle) { - std::puts("Failed to allocate DIO 28 (CS3)"); - CommonSPIPortFree(); - return; - } - spi->nativeHandle = open("/dev/spidev0.3", O_RDWR); - if (spi->nativeHandle < 0) { - wpi::print("Failed to open SPI port {}: {}\n", - static_cast(port), std::strerror(errno)); - CommonSPIPortFree(); - HAL_FreeDIOPort(digitalHandles[2]); - spiHandles->Free(hal_handle); - *status = INCOMPATIBLE_STATE; - return; - } + nativeHandle = InitOnboardCS3(status); break; case HAL_SPI_kMXP: - initializeDigital(status); - if (*status != 0) { - return; - } - if ((digitalHandles[5] = HAL_InitializeDIOPort(createPortHandleForSPI(14), - false, nullptr, status)) == - HAL_kInvalidHandle) { - std::puts("Failed to allocate DIO 14"); - return; - } - if ((digitalHandles[6] = HAL_InitializeDIOPort(createPortHandleForSPI(15), - false, nullptr, status)) == - HAL_kInvalidHandle) { - std::puts("Failed to allocate DIO 15"); - HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated - return; - } - if ((digitalHandles[7] = HAL_InitializeDIOPort(createPortHandleForSPI(16), - false, nullptr, status)) == - HAL_kInvalidHandle) { - std::puts("Failed to allocate DIO 16"); - HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated - HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated - return; - } - if ((digitalHandles[8] = HAL_InitializeDIOPort(createPortHandleForSPI(17), - false, nullptr, status)) == - HAL_kInvalidHandle) { - std::puts("Failed to allocate DIO 17"); - HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated - HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated - HAL_FreeDIOPort(digitalHandles[7]); // free the third port allocated - return; - } - digitalSystem->writeEnableMXPSpecialFunction( - digitalSystem->readEnableMXPSpecialFunction(status) | 0x00F0, status); - spi->nativeHandle = open("/dev/spidev1.0", O_RDWR); - if (spi->nativeHandle < 0) { - wpi::print("Failed to open SPI port {}: {}\n", - static_cast(port), std::strerror(errno)); - HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated - HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated - HAL_FreeDIOPort(digitalHandles[7]); // free the third port allocated - HAL_FreeDIOPort(digitalHandles[8]); // free the fourth port allocated - spiHandles->Free(hal_handle); - *status = INCOMPATIBLE_STATE; - return; - } + nativeHandle = InitMXP(status); break; default: // TODO: should be unreachable *status = PARAMETER_OUT_OF_RANGE; hal::SetLastError( status, fmt::format("Invalid SPI port {}", static_cast(port))); + return HAL_kInvalidHandle; break; } + if (*status != 0) { + spiHandles->Free(hal_handle); + return HAL_kInvalidHandle; + } + spi->nativeHandle = nativeHandle; + spi->port = port; + return hal_handle; } int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend, diff --git a/hal/src/main/native/include/hal/SPI.h b/hal/src/main/native/include/hal/SPI.h index d39f8938d93..1f6c4c7647a 100644 --- a/hal/src/main/native/include/hal/SPI.h +++ b/hal/src/main/native/include/hal/SPI.h @@ -30,7 +30,7 @@ extern "C" { * @param[in] port The port to initialize. * @param[out] status the error code, or 0 for success. */ -void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status); +HAL_SPIHandle HAL_InitializeSPI(HAL_SPIPort port, int32_t* status); /** * Performs an SPI send/receive transaction. diff --git a/hal/src/main/native/include/hal/Types.h b/hal/src/main/native/include/hal/Types.h index 1abb16e4774..d63e0bbc3df 100644 --- a/hal/src/main/native/include/hal/Types.h +++ b/hal/src/main/native/include/hal/Types.h @@ -70,6 +70,8 @@ typedef HAL_Handle HAL_REVPDHHandle; typedef HAL_Handle HAL_REVPHHandle; +typedef HAL_Handle HAL_SPIHandle; + typedef int32_t HAL_Bool; #ifdef __cplusplus diff --git a/hal/src/main/native/sim/SPI.cpp b/hal/src/main/native/sim/SPI.cpp index 0aadf2443a8..ecc841381b8 100644 --- a/hal/src/main/native/sim/SPI.cpp +++ b/hal/src/main/native/sim/SPI.cpp @@ -15,9 +15,11 @@ void InitializeSPI() {} extern "C" { -void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { +HAL_SPIHandle HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { hal::init::CheckInit(); SimSPIData[port].initialized = true; + // TODO: deal with this + return 0; } int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend, uint8_t* dataReceived, int32_t size) {