2021-06-04 16:01:38 +02:00
|
|
|
#include "SpiComIF.h"
|
2021-06-04 17:13:14 +02:00
|
|
|
#include "SpiCookie.h"
|
2021-06-04 16:01:38 +02:00
|
|
|
|
2021-06-04 17:13:14 +02:00
|
|
|
#include "fsfw/tasks/SemaphoreFactory.h"
|
|
|
|
#include "fsfw_hal/stm32h7/spi/spiCore.h"
|
|
|
|
|
|
|
|
#include "stm32h7xx_hal_gpio.h"
|
|
|
|
|
|
|
|
SpiComIF::SpiComIF(object_id_t objectId, SPI_TypeDef* spiInstance, SPI_HandleTypeDef* spiHandle,
|
|
|
|
spi::TransferModes transferMode): SystemObject(objectId), transferMode(transferMode),
|
|
|
|
spiHandle(spiHandle) {
|
|
|
|
if(spiHandle == nullptr) {
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::error << "SpiComIF::SpiComIF: Passed SPI handle invalid!" << std::endl;
|
|
|
|
#else
|
|
|
|
sif::printError("SpiComIF::SpiComIF: Passed SPI handle invalid!\n");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
spiHandle->Instance = spiInstance;
|
|
|
|
spiHandle->Init.DataSize = SPI_DATASIZE_8BIT;
|
|
|
|
spiHandle->Init.FirstBit = SPI_FIRSTBIT_MSB;
|
|
|
|
spiHandle->Init.TIMode = SPI_TIMODE_DISABLE;
|
|
|
|
spiHandle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
|
|
|
spiHandle->Init.CRCPolynomial = 7;
|
|
|
|
spiHandle->Init.CRCLength = SPI_CRC_LENGTH_8BIT;
|
|
|
|
spiHandle->Init.NSS = SPI_NSS_SOFT;
|
|
|
|
spiHandle->Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
|
|
|
|
spiHandle->Init.Direction = SPI_DIRECTION_2LINES;
|
|
|
|
// Recommended setting to avoid glitches
|
|
|
|
spiHandle->Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
|
|
|
|
spiHandle->Init.Mode = SPI_MODE_MASTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpiComIF::configureCacheMaintenanceOnTxBuffer(bool enable) {
|
|
|
|
this->cacheMaintenanceOnTxBuffer = enable;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SpiComIF::addDmaHandles(DMA_HandleTypeDef *txHandle, DMA_HandleTypeDef *rxHandle) {
|
|
|
|
set_dma_handles(txHandle, rxHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::initialize() {
|
|
|
|
if(transferMode == spi::TransferModes::DMA) {
|
|
|
|
DMA_HandleTypeDef *txHandle = nullptr;
|
|
|
|
DMA_HandleTypeDef *rxHandle = nullptr;
|
|
|
|
get_dma_handles(&txHandle, &rxHandle);
|
|
|
|
if(txHandle == nullptr or rxHandle == nullptr) {
|
|
|
|
sif::printError("SpiComIF::initialize: DMA handles not set!\n");
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(HAL_SPI_Init(spiHandle) != HAL_OK) {
|
|
|
|
sif::printWarning("SpiComIF::initialize: Error initializing SPI\n");
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
2021-06-04 16:01:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) {
|
2021-06-04 17:13:14 +02:00
|
|
|
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
|
|
|
if(spiCookie == nullptr) {
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::error < "SpiComIF::initializeInterface: Invalid cookie" << std::endl;
|
|
|
|
#else
|
|
|
|
sif::printError("SpiComIF::initializeInterface: Invalid cookie\n");
|
|
|
|
#endif
|
|
|
|
return NULLPOINTER;
|
|
|
|
}
|
|
|
|
|
2021-06-05 00:04:38 +02:00
|
|
|
if(transferMode == spi::TransferModes::DMA or transferMode == spi::TransferModes::INTERRUPT) {
|
|
|
|
spiSemaphore = SemaphoreFactory::instance()->createBinarySemaphore();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
spiMutex = MutexFactory::instance()->createMutex();
|
|
|
|
}
|
|
|
|
|
2021-06-04 17:13:14 +02:00
|
|
|
address_t spiAddress = spiCookie->getDeviceAddress();
|
|
|
|
|
|
|
|
auto iter = spiDeviceMap.find(spiAddress);
|
|
|
|
if(iter == spiDeviceMap.end()) {
|
|
|
|
size_t bufferSize = spiCookie->getMaxRecvSize();
|
|
|
|
SpiInstance spiInstance = {std::vector<uint8_t>(bufferSize)};
|
|
|
|
auto statusPair = spiDeviceMap.emplace(spiAddress, spiInstance);
|
|
|
|
if (not statusPair.second) {
|
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::error << "SpiComIF::initializeInterface: Failed to insert device with address " <<
|
|
|
|
spiAddress << "to SPI device map" << std::endl;
|
|
|
|
#else
|
|
|
|
sif::printError("SpiComIF::initializeInterface: Failed to insert device with address "
|
|
|
|
"%lu to SPI device map\n", static_cast<unsigned long>(spiAddress));
|
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto gpioPin = spiCookie->getChipSelectGpioPin();
|
|
|
|
auto gpioPort = spiCookie->getChipSelectGpioPort();
|
|
|
|
|
|
|
|
GPIO_InitTypeDef chipSelect = {};
|
2021-06-05 00:11:35 +02:00
|
|
|
chipSelect.Pin = gpioPin;
|
2021-06-04 17:13:14 +02:00
|
|
|
chipSelect.Mode = GPIO_MODE_OUTPUT_PP;
|
|
|
|
HAL_GPIO_Init(gpioPort, &chipSelect);
|
|
|
|
HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_SET);
|
2021-06-04 16:01:38 +02:00
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) {
|
2021-06-05 00:04:38 +02:00
|
|
|
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
|
|
|
if(spiCookie == nullptr) {
|
|
|
|
return NULLPOINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
spi::assignSpiMode(spiCookie->getSpiMode(), spiHandle);
|
|
|
|
spiHandle->Init.BaudRatePrescaler = spi::getPrescaler(HAL_RCC_GetHCLKFreq(),
|
|
|
|
spiCookie->getSpiSpeed());
|
|
|
|
auto iter = spiDeviceMap.find(spiCookie->getDeviceAddress());
|
|
|
|
if(iter == spiDeviceMap.end()) {
|
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
|
|
|
switch(transferMode) {
|
|
|
|
case(spi::TransferModes::POLLING): {
|
2021-06-05 00:11:35 +02:00
|
|
|
return handlePollingSendOperation(iter->second.replyBuffer.data(), spiCookie, sendData,
|
|
|
|
sendLen);
|
2021-06-05 00:04:38 +02:00
|
|
|
}
|
|
|
|
case(spi::TransferModes::INTERRUPT): {
|
2021-06-05 00:11:35 +02:00
|
|
|
return handleInterruptSendOperation(iter->second.replyBuffer.data(), spiCookie, sendData,
|
|
|
|
sendLen);
|
2021-06-05 00:04:38 +02:00
|
|
|
}
|
|
|
|
case(spi::TransferModes::DMA): {
|
2021-06-05 00:11:35 +02:00
|
|
|
return handleDmaSendOperation(iter->second.replyBuffer.data(), spiCookie, sendData,
|
|
|
|
sendLen);
|
2021-06-05 00:04:38 +02:00
|
|
|
}
|
|
|
|
}
|
2021-06-04 16:01:38 +02:00
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::getSendSuccess(CookieIF *cookie) {
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
2021-06-05 00:04:38 +02:00
|
|
|
void SpiComIF::setDefaultPollingTimeout(dur_millis_t timeout) {
|
|
|
|
this->defaultPollingTimeout = timeout;
|
|
|
|
}
|
|
|
|
|
2021-06-04 16:01:38 +02:00
|
|
|
ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) {
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
2021-06-05 00:04:38 +02:00
|
|
|
|
2021-06-05 00:11:35 +02:00
|
|
|
ReturnValue_t SpiComIF::handlePollingSendOperation(uint8_t* recvPtr, SpiCookie *spiCookie,
|
2021-06-05 00:04:38 +02:00
|
|
|
const uint8_t *sendData, size_t sendLen) {
|
|
|
|
auto gpioPort = spiCookie->getChipSelectGpioPort();
|
|
|
|
auto gpioPin = spiCookie->getChipSelectGpioPin();
|
|
|
|
spiMutex->lockMutex(timeoutType, timeoutMs);
|
|
|
|
HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_RESET);
|
|
|
|
auto result = HAL_SPI_TransmitReceive(spiHandle, const_cast<uint8_t*>(sendData),
|
2021-06-05 00:11:35 +02:00
|
|
|
recvPtr, sendLen, defaultPollingTimeout);
|
2021-06-05 00:04:38 +02:00
|
|
|
HAL_GPIO_WritePin(gpioPort, gpioPin, GPIO_PIN_SET);
|
|
|
|
spiMutex->unlockMutex();
|
|
|
|
switch(result) {
|
|
|
|
case(HAL_OK): {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(HAL_TIMEOUT): {
|
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::warning << "SpiComIF::sendMessage: Polling Mode | Timeout for SPI device" <<
|
|
|
|
spiCookie->getDeviceAddress() << std::endl;
|
|
|
|
#else
|
|
|
|
sif::printWarning("SpiComIF::sendMessage: Polling Mode | Timeout for SPI device %d\n",
|
|
|
|
spiCookie->getDeviceAddress());
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return spi::HAL_TIMEOUT_RETVAL;
|
|
|
|
}
|
|
|
|
case(HAL_ERROR):
|
|
|
|
default: {
|
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::warning << "SpiComIF::sendMessage: Polling Mode | HAL error for SPI device" <<
|
|
|
|
spiCookie->getDeviceAddress() << std::endl;
|
|
|
|
#else
|
|
|
|
sif::printWarning("SpiComIF::sendMessage: Polling Mode | HAL error for SPI device %d\n",
|
|
|
|
spiCookie->getDeviceAddress());
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return spi::HAL_ERROR_RETVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
2021-06-05 00:11:35 +02:00
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::handleInterruptSendOperation(uint8_t* recvPtr, SpiCookie* spiCookie,
|
|
|
|
const uint8_t * sendData, size_t sendLen) {
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SpiComIF::handleDmaSendOperation(uint8_t* recvPtr, SpiCookie* spiCookie,
|
|
|
|
const uint8_t * sendData, size_t sendLen) {
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
|
|
|
}
|