added callback functionality to spi

This commit is contained in:
Robin Müller 2021-05-23 21:34:59 +02:00
parent a0f698fffa
commit 9203a30bcf
5 changed files with 166 additions and 70 deletions

View File

@ -21,7 +21,7 @@
#endif #endif
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): SystemObject(objectId), SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): SystemObject(objectId),
gpioComIF(gpioComIF) { gpioComIF(gpioComIF) {
if(gpioComIF == nullptr) { if(gpioComIF == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 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; 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 */ bool fullDuplex = spiCookie->isFullDuplex();
int fileDescriptor = 0; gpioId_t gpioId = spiCookie->getChipSelectPin();
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(); /* Pull SPI CS low. For now, no support for active high given */
gpioId_t gpioId = spiCookie->getChipSelectPin(); if(gpioId != gpio::NO_GPIO) {
result = spiMutex->lockMutex(timeoutType, timeoutMs);
/* Pull SPI CS low. For now, no support for active high given */ if (result != RETURN_OK) {
if(gpioId != gpio::NO_GPIO) {
result = spiMutex->lockMutex(timeoutType, timeoutMs);
if (result != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #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 #endif
return result; return result;
}
gpioComIF->pullLow(gpioId);
} }
gpioComIF->pullLow(gpioId);
}
/* Execute transfer */ /* Execute transfer */
if(fullDuplex) { if(fullDuplex) {
/* Initiate a full duplex SPI transfer. */ /* Initiate a full duplex SPI transfer. */
retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle()); retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle());
if(retval < 0) { if(retval < 0) {
utility::handleIoctlError("SpiComIF::sendMessage: ioctl error."); utility::handleIoctlError("SpiComIF::sendMessage: ioctl error.");
result = FULL_DUPLEX_TRANSFER_FAILED; result = FULL_DUPLEX_TRANSFER_FAILED;
} }
#if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1 #if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1
size_t dataLen = spiCookie->getTransferStructHandle()->len; size_t dataLen = spiCookie->getTransferStructHandle()->len;
uint8_t* dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->tx_buf); uint8_t* dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->tx_buf);
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Sent SPI data: " << std::endl; sif::info << "Sent SPI data: " << std::endl;
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
sif::info << "Received SPI data: " << std::endl; sif::info << "Received SPI data: " << std::endl;
#else #else
sif::printInfo("Sent SPI data: \n"); sif::printInfo("Sent SPI data: \n");
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
sif::printInfo("Received SPI data: \n"); sif::printInfo("Received SPI data: \n");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->rx_buf); dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->rx_buf);
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */ #endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */
} }
else { else {
/* We write with a blocking half-duplex transfer here */ /* We write with a blocking half-duplex transfer here */
if (write(fileDescriptor, sendData, sendLen) != static_cast<ssize_t>(sendLen)) { if (write(fileDescriptor, sendData, sendLen) != static_cast<ssize_t>(sendLen)) {
#if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" <<
std::endl; std::endl;
#else #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_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 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; return result;
} }
@ -246,7 +256,6 @@ ReturnValue_t SpiComIF::getSendSuccess(CookieIF *cookie) {
} }
ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) { ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie); SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
if(spiCookie == nullptr) { if(spiCookie == nullptr) {
return NULLPOINTER; return NULLPOINTER;
@ -257,6 +266,12 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
return performHalfDuplexReception(spiCookie);
}
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
std::string device = spiCookie->getSpiDevice(); std::string device = spiCookie->getSpiDevice();
int fileDescriptor = 0; int fileDescriptor = 0;
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, 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) { ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) {

View File

@ -11,6 +11,8 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
class SpiCookie;
/** /**
* @brief Encapsulates access to linux SPI driver for FSFW objects * @brief Encapsulates access to linux SPI driver for FSFW objects
* @details * @details
@ -39,6 +41,7 @@ public:
size_t requestLen) override; size_t requestLen) override;
ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
size_t *size) override; size_t *size) override;
/** /**
* @brief This function returns the mutex which can be used to protect the spi bus when * @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. * the chip select must be driven from outside of the com if.
@ -61,6 +64,7 @@ private:
SpiDeviceMap spiDeviceMap; SpiDeviceMap spiDeviceMap;
ReturnValue_t performHalfDuplexReception(SpiCookie* spiCookie);
ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer); ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer);
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed); void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);

View File

@ -1,14 +1,33 @@
#include "SpiCookie.h" #include "SpiCookie.h"
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed): spiAddress(spiAddress), const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed):
chipSelectPin(chipSelect), spiDevice(spiDev), maxSize(maxSize), spiMode(spiMode), SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, spiDev, maxSize, spiMode,
spiSpeed(spiSpeed) { spiSpeed, nullptr, nullptr) {
} }
SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize, SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize,
spi::SpiModes spiMode, uint32_t spiSpeed): 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, 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() { spi_ioc_transfer* SpiCookie::getTransferStructHandle() {
return &spiTransferStruct; return &spiTransferStruct;
} }
@ -105,3 +131,9 @@ void SpiCookie::setSpiSpeed(uint32_t newSpeed) {
void SpiCookie::setSpiMode(spi::SpiModes newMode) { void SpiCookie::setSpiMode(spi::SpiModes newMode) {
this->spiMode = newMode; this->spiMode = newMode;
} }
void SpiCookie::getCallback(spi::send_callback_function_t *callback,
void **args) {
*callback = this->sendCallback;
*args = this->callbackArgs;
}

View File

@ -8,7 +8,6 @@
class SpiCookie: public CookieIF { class SpiCookie: public CookieIF {
public: public:
/** /**
* Each SPI device will have a corresponding cookie. The cookie is used by the communication * 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 * interface and contains device specific information like the largest expected size to be
@ -19,7 +18,7 @@ public:
* @param maxSize * @param maxSize
*/ */
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, 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 * 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, SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize,
spi::SpiModes spiMode, uint32_t spiSpeed); 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; address_t getSpiAddress() const;
std::string getSpiDevice() const; std::string getSpiDevice() const;
gpioId_t getChipSelectPin() const; gpioId_t getChipSelectPin() const;
size_t getMaxBufferSize() const; size_t getMaxBufferSize() const;
spi::SpiComIfModes getComIfMode() const;
/** Enables changing SPI speed at run-time */ /** Enables changing SPI speed at run-time */
void setSpiSpeed(uint32_t newSpeed); void setSpiSpeed(uint32_t newSpeed);
/** Enables changing the SPI mode at run-time */ /** Enables changing the SPI mode at run-time */
void setSpiMode(spi::SpiModes newMode); 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 * True if SPI transfers should be performed in full duplex mode
* @return * @return
@ -99,17 +111,40 @@ public:
spi_ioc_transfer* getTransferStructHandle(); spi_ioc_transfer* getTransferStructHandle();
private: 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; size_t currentTransferSize = 0;
address_t spiAddress; address_t spiAddress;
gpioId_t chipSelectPin; gpioId_t chipSelectPin;
std::string spiDevice; std::string spiDevice;
spi::SpiComIfModes comIfMode;
// Required for regular mode
const size_t maxSize; const size_t maxSize;
spi::SpiModes spiMode; spi::SpiModes spiMode;
uint32_t spiSpeed; uint32_t spiSpeed;
bool halfDuplex = false; bool halfDuplex = false;
// Required for callback mode
spi::send_callback_function_t sendCallback = nullptr;
void* callbackArgs = nullptr;
struct spi_ioc_transfer spiTransferStruct = {}; struct spi_ioc_transfer spiTransferStruct = {};
UncommonParameters uncommonParameters; UncommonParameters uncommonParameters;
}; };

View File

@ -1,6 +1,8 @@
#ifndef LINUX_SPI_SPIDEFINITONS_H_ #ifndef LINUX_SPI_SPIDEFINITONS_H_
#define LINUX_SPI_SPIDEFINITONS_H_ #define LINUX_SPI_SPIDEFINITONS_H_
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include <cstdint> #include <cstdint>
namespace spi { namespace spi {
@ -12,6 +14,14 @@ enum SpiModes: uint8_t {
MODE_3 MODE_3
}; };
enum SpiComIfModes {
REGULAR,
CALLBACK
};
using send_callback_function_t = ReturnValue_t (*) (uint8_t** replyData, void* args);
} }
#endif /* LINUX_SPI_SPIDEFINITONS_H_ */ #endif /* LINUX_SPI_SPIDEFINITONS_H_ */