2021-08-02 20:58:56 +02:00
|
|
|
#include "fsfw_hal/linux/spi/SpiComIF.h"
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
#include <fcntl.h>
|
2021-07-13 19:19:25 +02:00
|
|
|
#include <fsfw/globalfunctions/arrayprinter.h>
|
2022-02-02 10:29:30 +01:00
|
|
|
#include <fsfw/ipc/MutexFactory.h>
|
2021-07-13 19:19:25 +02:00
|
|
|
#include <linux/spi/spidev.h>
|
|
|
|
#include <sys/ioctl.h>
|
2022-02-02 10:29:30 +01:00
|
|
|
#include <unistd.h>
|
2021-07-13 19:19:25 +02:00
|
|
|
|
|
|
|
#include <cerrno>
|
|
|
|
#include <cstring>
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
#include "fsfw/FSFW.h"
|
|
|
|
#include "fsfw_hal/linux/UnixFileGuard.h"
|
|
|
|
#include "fsfw_hal/linux/spi/SpiCookie.h"
|
|
|
|
#include "fsfw_hal/linux/utility.h"
|
|
|
|
|
|
|
|
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF)
|
|
|
|
: SystemObject(objectId), gpioComIF(gpioComIF) {
|
|
|
|
if (gpioComIF == nullptr) {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::error << "SpiComIF::SpiComIF: GPIO communication interface invalid!" << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printError("SpiComIF::SpiComIF: GPIO communication interface invalid!\n");
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
spiMutex = MutexFactory::instance()->createMutex();
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
|
|
|
int retval = 0;
|
|
|
|
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
|
|
|
if (spiCookie == nullptr) {
|
|
|
|
return NULLPOINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
address_t spiAddress = spiCookie->getSpiAddress();
|
|
|
|
|
|
|
|
auto iter = spiDeviceMap.find(spiAddress);
|
|
|
|
if (iter == spiDeviceMap.end()) {
|
|
|
|
size_t bufferSize = spiCookie->getMaxBufferSize();
|
|
|
|
SpiInstance spiInstance(bufferSize);
|
|
|
|
auto statusPair = spiDeviceMap.emplace(spiAddress, spiInstance);
|
|
|
|
if (not statusPair.second) {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::error << "SpiComIF::initializeInterface: Failed to insert device with address "
|
|
|
|
<< spiAddress << "to SPI device map" << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printError(
|
|
|
|
"SpiComIF::initializeInterface: Failed to insert device with address "
|
|
|
|
"%lu to SPI device map\n",
|
|
|
|
static_cast<unsigned long>(spiAddress));
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
2022-02-02 10:29:30 +01:00
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
2022-02-02 10:29:30 +01:00
|
|
|
/* Now we emplaced the read buffer in the map, we still need to assign that location
|
|
|
|
to the SPI driver transfer struct */
|
|
|
|
spiCookie->assignReadBuffer(statusPair.first->second.replyBuffer.data());
|
|
|
|
} else {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::error << "SpiComIF::initializeInterface: SPI address already exists!" << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printError("SpiComIF::initializeInterface: SPI address already exists!\n");
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
2022-02-02 10:29:30 +01:00
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pull CS high in any case to be sure that device is inactive */
|
|
|
|
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
|
|
|
if (gpioId != gpio::NO_GPIO) {
|
|
|
|
gpioComIF->pullHigh(gpioId);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t spiSpeed = 0;
|
|
|
|
spi::SpiModes spiMode = spi::SpiModes::MODE_0;
|
|
|
|
|
|
|
|
SpiCookie::UncommonParameters params;
|
|
|
|
spiCookie->getSpiParameters(spiMode, spiSpeed, ¶ms);
|
|
|
|
|
|
|
|
int fileDescriptor = 0;
|
|
|
|
UnixFileGuard fileHelper(spiCookie->getSpiDevice(), &fileDescriptor, O_RDWR,
|
|
|
|
"SpiComIF::initializeInterface");
|
|
|
|
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
|
|
|
return fileHelper.getOpenResult();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* These flags are rather uncommon */
|
|
|
|
if (params.threeWireSpi or params.noCs or params.csHigh) {
|
|
|
|
uint32_t currentMode = 0;
|
|
|
|
retval = ioctl(fileDescriptor, SPI_IOC_RD_MODE32, ¤tMode);
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError("SpiComIF::initialiezInterface: Could not read full mode!");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params.threeWireSpi) {
|
|
|
|
currentMode |= SPI_3WIRE;
|
|
|
|
}
|
|
|
|
if (params.noCs) {
|
|
|
|
/* Some drivers like the Raspberry Pi ignore this flag in any case */
|
|
|
|
currentMode |= SPI_NO_CS;
|
|
|
|
}
|
|
|
|
if (params.csHigh) {
|
|
|
|
currentMode |= SPI_CS_HIGH;
|
|
|
|
}
|
|
|
|
/* Write adapted mode */
|
|
|
|
retval = ioctl(fileDescriptor, SPI_IOC_WR_MODE32, ¤tMode);
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError("SpiComIF::initialiezInterface: Could not write full mode!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (params.lsbFirst) {
|
|
|
|
retval = ioctl(fileDescriptor, SPI_IOC_WR_LSB_FIRST, ¶ms.lsbFirst);
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError("SpiComIF::initializeInterface: Setting LSB first failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (params.bitsPerWord != 8) {
|
|
|
|
retval = ioctl(fileDescriptor, SPI_IOC_WR_BITS_PER_WORD, ¶ms.bitsPerWord);
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError(
|
|
|
|
"SpiComIF::initializeInterface: "
|
|
|
|
"Could not write bits per word!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SpiComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) {
|
|
|
|
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
|
|
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if (spiCookie == nullptr) {
|
|
|
|
return NULLPOINTER;
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if (sendLen > spiCookie->getMaxBufferSize()) {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "SpiComIF::sendMessage: Too much data sent, send length " << sendLen
|
|
|
|
<< "larger than maximum buffer length " << spiCookie->getMaxBufferSize()
|
|
|
|
<< std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printWarning(
|
|
|
|
"SpiComIF::sendMessage: Too much data sent, send length %lu larger "
|
|
|
|
"than maximum buffer length %lu!\n",
|
|
|
|
static_cast<unsigned long>(sendLen),
|
|
|
|
static_cast<unsigned long>(spiCookie->getMaxBufferSize()));
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
2022-02-02 10:29:30 +01:00
|
|
|
return DeviceCommunicationIF::TOO_MUCH_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spiCookie->getComIfMode() == spi::SpiComIfModes::REGULAR) {
|
|
|
|
result = performRegularSendOperation(spiCookie, sendData, sendLen);
|
|
|
|
} else if (spiCookie->getComIfMode() == spi::SpiComIfModes::CALLBACK) {
|
|
|
|
spi::send_callback_function_t sendFunc = nullptr;
|
|
|
|
void* funcArgs = nullptr;
|
|
|
|
spiCookie->getCallback(&sendFunc, &funcArgs);
|
|
|
|
if (sendFunc != nullptr) {
|
|
|
|
result = sendFunc(this, spiCookie, sendData, sendLen, funcArgs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const uint8_t* sendData,
|
|
|
|
size_t sendLen) {
|
|
|
|
address_t spiAddress = spiCookie->getSpiAddress();
|
|
|
|
auto iter = spiDeviceMap.find(spiAddress);
|
|
|
|
if (iter != spiDeviceMap.end()) {
|
|
|
|
spiCookie->assignReadBuffer(iter->second.replyBuffer.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
|
|
int retval = 0;
|
|
|
|
/* 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->setTransferSize(sendLen);
|
|
|
|
|
|
|
|
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) {
|
2021-09-23 18:06:04 +02:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl;
|
2021-09-23 18:06:04 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printError("SpiComIF::sendMessage: Failed to lock mutex\n");
|
2021-09-23 18:06:04 +02:00
|
|
|
#endif
|
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
ReturnValue_t result = gpioComIF->pullLow(gpioId);
|
|
|
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
2021-09-23 18:06:04 +02:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "SpiComIF::sendMessage: Pulling low CS pin failed" << std::endl;
|
2021-09-23 18:06:04 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printWarning("SpiComIF::sendMessage: Pulling low CS pin failed");
|
2021-09-23 18:06:04 +02:00
|
|
|
#endif
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
return result;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
/* 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;
|
|
|
|
}
|
2021-09-23 18:06:04 +02:00
|
|
|
#if FSFW_HAL_SPI_WIRETAPPING == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
performSpiWiretapping(spiCookie);
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */
|
2022-02-02 10:29:30 +01:00
|
|
|
} else {
|
|
|
|
/* We write with a blocking half-duplex transfer here */
|
|
|
|
if (write(fileDescriptor, sendData, sendLen) != static_cast<ssize_t>(sendLen)) {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n");
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
2022-02-02 10:29:30 +01:00
|
|
|
result = HALF_DUPLEX_TRANSFER_FAILED;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if (gpioId != gpio::NO_GPIO) {
|
|
|
|
gpioComIF->pullHigh(gpioId);
|
|
|
|
result = spiMutex->unlockMutex();
|
|
|
|
if (result != RETURN_OK) {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
return result;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
|
|
|
return result;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SpiComIF::getSendSuccess(CookieIF* cookie) { return HasReturnvaluesIF::RETURN_OK; }
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLen) {
|
|
|
|
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
|
|
|
if (spiCookie == nullptr) {
|
|
|
|
return NULLPOINTER;
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if (spiCookie->isFullDuplex()) {
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
return performHalfDuplexReception(spiCookie);
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
|
|
|
std::string device = spiCookie->getSpiDevice();
|
|
|
|
int fileDescriptor = 0;
|
|
|
|
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
|
|
|
|
if (fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
|
|
|
return OPENING_FILE_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t* rxBuf = nullptr;
|
|
|
|
size_t readSize = spiCookie->getCurrentTransferSize();
|
|
|
|
result = getReadBuffer(spiCookie->getSpiAddress(), &rxBuf);
|
|
|
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
|
|
return result;
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
|
|
|
if (gpioId != gpio::NO_GPIO) {
|
|
|
|
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
|
|
|
if (result != RETURN_OK) {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
return result;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
2022-02-02 10:29:30 +01:00
|
|
|
gpioComIF->pullLow(gpioId);
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if (read(fileDescriptor, rxBuf, readSize) != static_cast<ssize_t>(readSize)) {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::warning << "SpiComIF::sendMessage: Half-Duplex read operation failed!" << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printWarning("SpiComIF::sendMessage: Half-Duplex read operation failed!\n");
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
2022-02-02 10:29:30 +01:00
|
|
|
result = HALF_DUPLEX_TRANSFER_FAILED;
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if (gpioId != gpio::NO_GPIO) {
|
|
|
|
gpioComIF->pullHigh(gpioId);
|
|
|
|
result = spiMutex->unlockMutex();
|
|
|
|
if (result != RETURN_OK) {
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
return result;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
return result;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SpiComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer, size_t* size) {
|
|
|
|
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
|
|
|
if (spiCookie == nullptr) {
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
uint8_t* rxBuf = nullptr;
|
|
|
|
ReturnValue_t result = getReadBuffer(spiCookie->getSpiAddress(), &rxBuf);
|
|
|
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
|
|
return result;
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
*buffer = rxBuf;
|
|
|
|
*size = spiCookie->getCurrentTransferSize();
|
|
|
|
spiCookie->setTransferSize(0);
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) {
|
2022-02-02 10:29:30 +01:00
|
|
|
if (timeoutType != nullptr) {
|
|
|
|
*timeoutType = this->timeoutType;
|
|
|
|
}
|
|
|
|
if (timeoutMs != nullptr) {
|
|
|
|
*timeoutMs = this->timeoutMs;
|
|
|
|
}
|
|
|
|
return spiMutex;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
|
2022-02-02 10:29:30 +01:00
|
|
|
if (spiCookie == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
size_t dataLen = spiCookie->getTransferStructHandle()->len;
|
|
|
|
uint8_t* dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->tx_buf);
|
2021-07-13 19:19:25 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::info << "Sent SPI data: " << std::endl;
|
|
|
|
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
|
|
|
sif::info << "Received SPI data: " << std::endl;
|
2021-07-13 19:19:25 +02:00
|
|
|
#else
|
2022-02-02 10:29:30 +01:00
|
|
|
sif::printInfo("Sent SPI data: \n");
|
|
|
|
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
|
|
|
sif::printInfo("Received SPI data: \n");
|
2021-07-13 19:19:25 +02:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
2022-02-02 10:29:30 +01:00
|
|
|
dataPtr = reinterpret_cast<uint8_t*>(spiCookie->getTransferStructHandle()->rx_buf);
|
|
|
|
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
|
2022-02-02 10:29:30 +01:00
|
|
|
if (buffer == nullptr) {
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
auto iter = spiDeviceMap.find(spiAddress);
|
|
|
|
if (iter == spiDeviceMap.end()) {
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
*buffer = iter->second.replyBuffer.data();
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
GpioIF* SpiComIF::getGpioInterface() { return gpioComIF; }
|
2021-07-13 19:19:25 +02:00
|
|
|
|
|
|
|
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) {
|
2022-02-02 10:29:30 +01:00
|
|
|
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI mode failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
|
|
|
}
|
2022-03-07 16:13:04 +01:00
|
|
|
// This updates the SPI clock default polarity. Only setting the mode does not update
|
|
|
|
// the line state, which can be an issue on mode switches because the clock line will
|
|
|
|
// switch the state after the chip select is pulled low
|
|
|
|
clockUpdateTransfer.len = 0;
|
|
|
|
retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
|
|
|
|
}
|
2021-07-13 19:19:25 +02:00
|
|
|
}
|
2022-05-11 10:54:13 +02:00
|
|
|
|
|
|
|
void SpiComIF::getSpiSpeedAndMode(int spiFd, spi::SpiModes &mode, uint32_t &speed) const {
|
|
|
|
uint8_t tmpMode = 0;
|
|
|
|
int retval = ioctl(spiFd, SPI_IOC_RD_MODE, &tmpMode);
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Reading SPI mode failed");
|
|
|
|
}
|
|
|
|
mode = static_cast<spi::SpiModes>(tmpMode);
|
|
|
|
|
|
|
|
retval = ioctl(spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
|
|
|
if (retval != 0) {
|
|
|
|
utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Getting SPI speed failed");
|
|
|
|
}
|
|
|
|
}
|