diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index 9225adb..3cc81f8 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -21,7 +21,7 @@ #endif SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): SystemObject(objectId), - gpioComIF(gpioComIF) { +gpioComIF(gpioComIF) { if(gpioComIF == nullptr) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -158,86 +158,96 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s return DeviceCommunicationIF::TOO_MUCH_DATA; } + if(spiCookie->getComIfMode() == spi::SpiComIfModes::REGULAR) { + /* Prepare transfer */ + int fileDescriptor = 0; + std::string device = spiCookie->getSpiDevice(); + UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, + "SpiComIF::sendMessage: "); + if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { + return OPENING_FILE_FAILED; + } + spi::SpiModes spiMode = spi::SpiModes::MODE_0; + uint32_t spiSpeed = 0; + spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); + setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); + spiCookie->assignWriteBuffer(sendData); + spiCookie->assignTransferSize(sendLen); - /* Prepare transfer */ - int fileDescriptor = 0; - std::string device = spiCookie->getSpiDevice(); - UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, - "SpiComIF::sendMessage: "); - if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { - return OPENING_FILE_FAILED; - } - spi::SpiModes spiMode = spi::SpiModes::MODE_0; - uint32_t spiSpeed = 0; - spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); - setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); - spiCookie->assignWriteBuffer(sendData); - spiCookie->assignTransferSize(sendLen); + bool fullDuplex = spiCookie->isFullDuplex(); + gpioId_t gpioId = spiCookie->getChipSelectPin(); - bool fullDuplex = spiCookie->isFullDuplex(); - gpioId_t gpioId = spiCookie->getChipSelectPin(); - - /* Pull SPI CS low. For now, no support for active high given */ - if(gpioId != gpio::NO_GPIO) { - result = spiMutex->lockMutex(timeoutType, timeoutMs); - if (result != RETURN_OK) { + /* Pull SPI CS low. For now, no support for active high given */ + if(gpioId != gpio::NO_GPIO) { + result = spiMutex->lockMutex(timeoutType, timeoutMs); + if (result != RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl; + sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl; #endif - return result; + return result; + } + gpioComIF->pullLow(gpioId); } - gpioComIF->pullLow(gpioId); - } - /* Execute transfer */ - if(fullDuplex) { - /* Initiate a full duplex SPI transfer. */ - retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle()); - if(retval < 0) { - utility::handleIoctlError("SpiComIF::sendMessage: ioctl error."); - result = FULL_DUPLEX_TRANSFER_FAILED; - } + /* Execute transfer */ + if(fullDuplex) { + /* Initiate a full duplex SPI transfer. */ + retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle()); + if(retval < 0) { + utility::handleIoctlError("SpiComIF::sendMessage: ioctl error."); + result = FULL_DUPLEX_TRANSFER_FAILED; + } #if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1 - size_t dataLen = spiCookie->getTransferStructHandle()->len; - uint8_t* dataPtr = reinterpret_cast(spiCookie->getTransferStructHandle()->tx_buf); + size_t dataLen = spiCookie->getTransferStructHandle()->len; + uint8_t* dataPtr = reinterpret_cast(spiCookie->getTransferStructHandle()->tx_buf); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << "Sent SPI data: " << std::endl; - arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); - sif::info << "Received SPI data: " << std::endl; + sif::info << "Sent SPI data: " << std::endl; + arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); + sif::info << "Received SPI data: " << std::endl; #else - sif::printInfo("Sent SPI data: \n"); - arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); - sif::printInfo("Received SPI data: \n"); + sif::printInfo("Sent SPI data: \n"); + arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); + sif::printInfo("Received SPI data: \n"); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ - dataPtr = reinterpret_cast(spiCookie->getTransferStructHandle()->rx_buf); - arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); + dataPtr = reinterpret_cast(spiCookie->getTransferStructHandle()->rx_buf); + arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); #endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */ - } - else { - /* We write with a blocking half-duplex transfer here */ - if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { + } + else { + /* We write with a blocking half-duplex transfer here */ + if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << - std::endl; + sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << + std::endl; #else - sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n"); + sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n"); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ - result = HALF_DUPLEX_TRANSFER_FAILED; + result = HALF_DUPLEX_TRANSFER_FAILED; + } + } + + if(gpioId != gpio::NO_GPIO) { + gpioComIF->pullHigh(gpioId); + result = spiMutex->unlockMutex(); + if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl; +#endif + return result; + } + } + } + else if(spiCookie->getComIfMode() == spi::SpiComIfModes::CALLBACK) { + spi::send_callback_function_t sendFunc = nullptr; + void* funcArgs = nullptr; + spiCookie->getCallback(&sendFunc, &funcArgs); + if(sendFunc != nullptr) { + // sendFunc() } } - if(gpioId != gpio::NO_GPIO) { - gpioComIF->pullHigh(gpioId); - result = spiMutex->unlockMutex(); - if (result != RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl; -#endif - return result; - } - } return result; } @@ -246,7 +256,6 @@ ReturnValue_t SpiComIF::getSendSuccess(CookieIF *cookie) { } ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; SpiCookie* spiCookie = dynamic_cast(cookie); if(spiCookie == nullptr) { return NULLPOINTER; @@ -257,6 +266,12 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe return HasReturnvaluesIF::RETURN_OK; } + return performHalfDuplexReception(spiCookie); +} + + +ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; std::string device = spiCookie->getSpiDevice(); int fileDescriptor = 0; UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, @@ -306,7 +321,7 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe } } - return HasReturnvaluesIF::RETURN_OK; + return result; } ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) { diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index 9228994..ddb7761 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -11,6 +11,8 @@ #include #include +class SpiCookie; + /** * @brief Encapsulates access to linux SPI driver for FSFW objects * @details @@ -39,6 +41,7 @@ public: size_t requestLen) override; ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) override; + /** * @brief This function returns the mutex which can be used to protect the spi bus when * the chip select must be driven from outside of the com if. @@ -61,6 +64,7 @@ private: SpiDeviceMap spiDeviceMap; + ReturnValue_t performHalfDuplexReception(SpiCookie* spiCookie); ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer); void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed); diff --git a/linux/spi/SpiCookie.cpp b/linux/spi/SpiCookie.cpp index 9111768..07acf28 100644 --- a/linux/spi/SpiCookie.cpp +++ b/linux/spi/SpiCookie.cpp @@ -1,14 +1,33 @@ #include "SpiCookie.h" SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, - const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed): spiAddress(spiAddress), - chipSelectPin(chipSelect), spiDevice(spiDev), maxSize(maxSize), spiMode(spiMode), - spiSpeed(spiSpeed) { + const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed): + SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, spiDev, maxSize, spiMode, + spiSpeed, nullptr, nullptr) { + } SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed): - SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) { + SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) { +} + +SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize, + spi::send_callback_function_t callback, void *args): + SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, gpio::NO_GPIO, spiDev, maxSize, + spi::SpiModes::MODE_0, 0, callback, args) { +} + +SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect, + std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, + spi::send_callback_function_t callback, void* args): spiAddress(spiAddress), + chipSelectPin(chipSelect), spiDevice(spiDev), comIfMode(comIfMode), + maxSize(maxSize), spiMode(spiMode), spiSpeed(spiSpeed), sendCallback(callback), + callbackArgs(args) { +} + +spi::SpiComIfModes SpiCookie::getComIfMode() const { + return this->comIfMode; } void SpiCookie::getSpiParameters(spi::SpiModes& spiMode, uint32_t& spiSpeed, @@ -78,6 +97,13 @@ void SpiCookie::assignWriteBuffer(const uint8_t* tx) { } } +void SpiCookie::setCallbackMode(spi::send_callback_function_t callback, + void *args) { + this->comIfMode = spi::SpiComIfModes::CALLBACK; + this->sendCallback = callback; + this->callbackArgs = args; +} + spi_ioc_transfer* SpiCookie::getTransferStructHandle() { return &spiTransferStruct; } @@ -105,3 +131,9 @@ void SpiCookie::setSpiSpeed(uint32_t newSpeed) { void SpiCookie::setSpiMode(spi::SpiModes newMode) { this->spiMode = newMode; } + +void SpiCookie::getCallback(spi::send_callback_function_t *callback, + void **args) { + *callback = this->sendCallback; + *args = this->callbackArgs; +} diff --git a/linux/spi/SpiCookie.h b/linux/spi/SpiCookie.h index aff4d77..a686249 100644 --- a/linux/spi/SpiCookie.h +++ b/linux/spi/SpiCookie.h @@ -8,7 +8,6 @@ class SpiCookie: public CookieIF { public: - /** * Each SPI device will have a corresponding cookie. The cookie is used by the communication * interface and contains device specific information like the largest expected size to be @@ -19,7 +18,7 @@ public: * @param maxSize */ SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, - const size_t maxReplySize, spi::SpiModes spiMode, uint32_t spiSpeed); + const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed); /** * Like constructor above, but without a dedicated GPIO CS. Can be used for hardware @@ -28,16 +27,29 @@ public: SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize, spi::SpiModes spiMode, uint32_t spiSpeed); + /** + * Use the callback mode of the SPI communication interface. The user can pass the callback + * function here or by using the setter function #setCallbackMode + */ + SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize, + spi::send_callback_function_t callback, void *args); + + void getCallback(spi::send_callback_function_t* callback, void** args); + address_t getSpiAddress() const; std::string getSpiDevice() const; gpioId_t getChipSelectPin() const; size_t getMaxBufferSize() const; + spi::SpiComIfModes getComIfMode() const; + /** Enables changing SPI speed at run-time */ void setSpiSpeed(uint32_t newSpeed); /** Enables changing the SPI mode at run-time */ void setSpiMode(spi::SpiModes newMode); + void setCallbackMode(spi::send_callback_function_t callback, void* args); + /** * True if SPI transfers should be performed in full duplex mode * @return @@ -99,17 +111,40 @@ public: spi_ioc_transfer* getTransferStructHandle(); private: + + /** + * Internal constructor which initializes every field + * @param spiAddress + * @param chipSelect + * @param spiDev + * @param maxSize + * @param spiMode + * @param spiSpeed + * @param callback + * @param args + */ + SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect, + std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, + spi::send_callback_function_t callback, void* args); + size_t currentTransferSize = 0; address_t spiAddress; gpioId_t chipSelectPin; std::string spiDevice; + spi::SpiComIfModes comIfMode; + + // Required for regular mode const size_t maxSize; spi::SpiModes spiMode; uint32_t spiSpeed; bool halfDuplex = false; + // Required for callback mode + spi::send_callback_function_t sendCallback = nullptr; + void* callbackArgs = nullptr; + struct spi_ioc_transfer spiTransferStruct = {}; UncommonParameters uncommonParameters; }; diff --git a/linux/spi/spiDefinitions.h b/linux/spi/spiDefinitions.h index e8c4814..c131038 100644 --- a/linux/spi/spiDefinitions.h +++ b/linux/spi/spiDefinitions.h @@ -1,6 +1,8 @@ #ifndef LINUX_SPI_SPIDEFINITONS_H_ #define LINUX_SPI_SPIDEFINITONS_H_ +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + #include namespace spi { @@ -12,6 +14,14 @@ enum SpiModes: uint8_t { MODE_3 }; +enum SpiComIfModes { + REGULAR, + CALLBACK +}; + + +using send_callback_function_t = ReturnValue_t (*) (uint8_t** replyData, void* args); + } #endif /* LINUX_SPI_SPIDEFINITONS_H_ */