18 Commits

Author SHA1 Message Date
61d7c61852 resetting reply buffer for regular send 2021-05-25 14:01:42 +02:00
c2b4231802 default wiretapping off 2021-05-25 13:52:39 +02:00
2893da047b extracted wiretapping function 2021-05-25 12:45:11 +02:00
bf8f3db41c some tweaks to make callback usage more easy 2021-05-25 12:14:22 +02:00
73a427d7e0 function is public now 2021-05-24 20:33:43 +02:00
f363d0fbd5 com if passed to callback as well 2021-05-24 19:11:01 +02:00
d801319c12 small fixes 2021-05-24 01:20:16 +02:00
2fe1a66836 added callback function 2021-05-24 00:13:59 +02:00
9203a30bcf added callback functionality to spi 2021-05-23 21:34:59 +02:00
a0f698fffa Merge pull request 'wrapped mutex error printout in preprocessor defines' (#6) from meier/master into master
Reviewed-on: fsfw/fsfw_hal#6
2021-05-12 18:13:05 +02:00
6341da2212 Merge branch 'master' into meier/master 2021-05-12 18:12:42 +02:00
e5da8b194d wrapped mutex error printout in preprocessor defines 2021-05-12 18:06:03 +02:00
c601e1dff7 Merge pull request 'fixed mutex bug' (#5) from meier/master into master
Reviewed-on: fsfw/fsfw_hal#5
2021-05-12 17:57:40 +02:00
d929352417 Merge branch 'master' into meier/master 2021-05-12 17:55:34 +02:00
49da48dc0d fixed mutex bug 2021-05-12 17:40:14 +02:00
99ba9d9346 Merge pull request 'meier/master' (#3) from meier/master into master
Reviewed-on: fsfw/fsfw_hal#3
2021-05-12 10:57:03 +02:00
425cfd2aba Merge branch 'master' into meier/master 2021-05-12 10:39:53 +02:00
8a38c7958b spi mutex only blocked when gpio != NO_GPIO 2021-05-12 10:22:23 +02:00
6 changed files with 219 additions and 40 deletions

View File

@@ -82,7 +82,7 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular
chipname = regularGpio->chipname;
chip = gpiod_chip_open_by_name(chipname.c_str());
if (!chip) {
sif::warning << "LinuxLibgpioIF::configureGpios: Failed to open chip "
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open chip "
<< chipname << ". Gpio ID: " << gpioId << std::endl;
return RETURN_FAILED;
}
@@ -90,9 +90,10 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular
lineNum = regularGpio->lineNum;
lineHandle = gpiod_chip_get_line(chip, lineNum);
if (!lineHandle) {
sif::warning << "LinuxLibgpioIF::configureGpios: Failed to open line for GPIO" << std::endl;
sif::warning << "GPIO ID " << gpioId << "with line number " << lineNum <<
" and chipname " << chipname << std::endl;
sif::debug << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl;
sif::debug << "GPIO ID: " << gpioId << ", line number: " << lineNum <<
", chipname: " << chipname << std::endl;
sif::debug << "Check if linux GPIO configuration has changed. " << std::endl;
gpiod_chip_close(chip);
return RETURN_FAILED;
}
@@ -105,7 +106,7 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, GpiodRegular
result = gpiod_line_request_output(lineHandle, consumer.c_str(),
regularGpio->initValue);
if (result < 0) {
sif::error << "LinuxLibgpioIF::configureGpios: Failed to request line " << lineNum <<
sif::error << "LinuxLibgpioIF::configureRegularGpio: Failed to request line " << lineNum <<
" from GPIO instance with ID: " << gpioId << std::endl;
gpiod_line_release(lineHandle);
return RETURN_FAILED;

View File

@@ -2,10 +2,9 @@
#include "SpiCookie.h"
#include "../utility.h"
#include "../UnixFileGuard.h"
#include <FSFWConfig.h>
#include "FSFWConfig.h"
#include <fsfw/ipc/MutexFactory.h>
#include <fsfw/ipc/MutexGuard.h>
#include <fsfw/globalfunctions/arrayprinter.h>
#include <linux/spi/spidev.h>
@@ -18,11 +17,11 @@
/* Can be used for low-level debugging of the SPI bus */
#ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING
#define FSFW_HAL_LINUX_SPI_WIRETAPPING 1
#define FSFW_HAL_LINUX_SPI_WIRETAPPING 0
#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
@@ -139,7 +138,6 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) {
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;
int retval = 0;
if(spiCookie == nullptr) {
return NULLPOINTER;
@@ -159,12 +157,34 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
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;
}
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: ");
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage: ");
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
return OPENING_FILE_FAILED;
}
@@ -178,11 +198,15 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
bool fullDuplex = spiCookie->isFullDuplex();
gpioId_t gpioId = spiCookie->getChipSelectPin();
/* GPIO access is mutex protected */
MutexGuard(spiMutex, timeoutType, timeoutMs);
/* 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;
#endif
return result;
}
gpioComIF->pullLow(gpioId);
}
@@ -195,19 +219,7 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
result = FULL_DUPLEX_TRANSFER_FAILED;
}
#if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1
size_t dataLen = spiCookie->getTransferStructHandle()->len;
uint8_t* dataPtr = reinterpret_cast<uint8_t*>(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;
#else
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<uint8_t*>(spiCookie->getTransferStructHandle()->rx_buf);
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
performSpiWiretapping(spiCookie);
#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */
}
else {
@@ -227,6 +239,13 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
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;
}
@@ -236,17 +255,21 @@ 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<SpiCookie*>(cookie);
if(spiCookie == nullptr) {
return NULLPOINTER;
}
bool fullDuplex = spiCookie->isFullDuplex();
if(fullDuplex) {
if(spiCookie->isFullDuplex()) {
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,
@@ -263,8 +286,14 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe
}
gpioId_t gpioId = spiCookie->getChipSelectPin();
MutexGuard(spiMutex, timeoutType, timeoutMs);
if(gpioId != gpio::NO_GPIO) {
result = spiMutex->lockMutex(timeoutType, timeoutMs);
if (result != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl;
#endif
return result;
}
gpioComIF->pullLow(gpioId);
}
@@ -281,9 +310,16 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe
if(gpioId != gpio::NO_GPIO) {
gpioComIF->pullHigh(gpioId);
result = spiMutex->unlockMutex();
if (result != RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl;
#endif
return result;
}
}
return HasReturnvaluesIF::RETURN_OK;
return result;
}
ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) {
@@ -302,6 +338,35 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
return HasReturnvaluesIF::RETURN_OK;
}
MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) {
if(timeoutType != nullptr) {
*timeoutType = this->timeoutType;
}
if(timeoutMs != nullptr) {
*timeoutMs = this->timeoutMs;
}
return spiMutex;
}
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
if(spiCookie == nullptr) {
return;
}
size_t dataLen = spiCookie->getTransferStructHandle()->len;
uint8_t* dataPtr = reinterpret_cast<uint8_t*>(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;
#else
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<uint8_t*>(spiCookie->getTransferStructHandle()->rx_buf);
arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false);
}
ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
if(buffer == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
@@ -316,6 +381,10 @@ ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
return HasReturnvaluesIF::RETURN_OK;
}
GpioIF* SpiComIF::getGpioInterface() {
return gpioComIF;
}
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) {
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
if(retval != 0) {

View File

@@ -11,6 +11,8 @@
#include <vector>
#include <unordered_map>
class SpiCookie;
/**
* @brief Encapsulates access to linux SPI driver for FSFW objects
* @details
@@ -39,6 +41,28 @@ 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.
*/
MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr);
/**
* Perform a regular send operation using Linux iotcl. This is public so it can be used
* in the user callback if special handling is only necessary for certain commands.
* @param spiCookie
* @param sendData
* @param sendLen
* @return
*/
ReturnValue_t performRegularSendOperation(SpiCookie* spiCookie, const uint8_t *sendData,
size_t sendLen);
GpioIF* getGpioInterface();
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);
void performSpiWiretapping(SpiCookie* spiCookie);
private:
struct SpiInstance {
@@ -56,9 +80,10 @@ 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);
};
#endif /* LINUX_SPI_SPICOMIF_H_ */

View File

@@ -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, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback, void *args):
SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize,
spiMode, spiSpeed, 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;
}

View File

@@ -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, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
spi::SpiModes spiMode, uint32_t spiSpeed, 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;
};

View File

@@ -1,8 +1,16 @@
#ifndef LINUX_SPI_SPIDEFINITONS_H_
#define LINUX_SPI_SPIDEFINITONS_H_
#include "../../common/gpio/gpioDefinitions.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
#include <linux/spi/spidev.h>
#include <cstdint>
class SpiCookie;
class SpiComIF;
namespace spi {
enum SpiModes: uint8_t {
@@ -12,6 +20,15 @@ enum SpiModes: uint8_t {
MODE_3
};
enum SpiComIfModes {
REGULAR,
CALLBACK
};
using send_callback_function_t = ReturnValue_t (*) (SpiComIF* comIf, SpiCookie *cookie,
const uint8_t *sendData, size_t sendLen, void* args);
}
#endif /* LINUX_SPI_SPIDEFINITONS_H_ */