Spi COM IF update #7
@ -10,3 +10,4 @@ target_sources(${LIB_FSFW_HAL_NAME} PRIVATE
|
|||||||
add_subdirectory(gpio)
|
add_subdirectory(gpio)
|
||||||
add_subdirectory(spi)
|
add_subdirectory(spi)
|
||||||
add_subdirectory(i2c)
|
add_subdirectory(i2c)
|
||||||
|
add_subdirectory(uart)
|
@ -2,7 +2,7 @@
|
|||||||
#include "SpiCookie.h"
|
#include "SpiCookie.h"
|
||||||
#include "../utility.h"
|
#include "../utility.h"
|
||||||
#include "../UnixFileGuard.h"
|
#include "../UnixFileGuard.h"
|
||||||
#include <FSFWConfig.h>
|
#include "FSFWConfig.h"
|
||||||
|
|
||||||
#include <fsfw/ipc/MutexFactory.h>
|
#include <fsfw/ipc/MutexFactory.h>
|
||||||
#include <fsfw/globalfunctions/arrayprinter.h>
|
#include <fsfw/globalfunctions/arrayprinter.h>
|
||||||
@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
/* Can be used for low-level debugging of the SPI bus */
|
/* Can be used for low-level debugging of the SPI bus */
|
||||||
#ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING
|
#ifndef FSFW_HAL_LINUX_SPI_WIRETAPPING
|
||||||
#define FSFW_HAL_LINUX_SPI_WIRETAPPING 1
|
#define FSFW_HAL_LINUX_SPI_WIRETAPPING 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): SystemObject(objectId),
|
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF):
|
||||||
gpioComIF(gpioComIF) {
|
SystemObject(objectId), 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
|
||||||
@ -138,7 +138,6 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF *cookie) {
|
|||||||
ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) {
|
ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) {
|
||||||
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
SpiCookie* spiCookie = dynamic_cast<SpiCookie*>(cookie);
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
if(spiCookie == nullptr) {
|
if(spiCookie == nullptr) {
|
||||||
return NULLPOINTER;
|
return NULLPOINTER;
|
||||||
@ -158,12 +157,34 @@ 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) {
|
||||||
|
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 */
|
/* Prepare transfer */
|
||||||
int fileDescriptor = 0;
|
int fileDescriptor = 0;
|
||||||
std::string device = spiCookie->getSpiDevice();
|
std::string device = spiCookie->getSpiDevice();
|
||||||
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR,
|
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage: ");
|
||||||
"SpiComIF::sendMessage: ");
|
|
||||||
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return OPENING_FILE_FAILED;
|
return OPENING_FILE_FAILED;
|
||||||
}
|
}
|
||||||
@ -198,19 +219,7 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s
|
|||||||
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;
|
performSpiWiretapping(spiCookie);
|
||||||
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);
|
|
||||||
#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */
|
#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -246,17 +255,21 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fullDuplex = spiCookie->isFullDuplex();
|
if(spiCookie->isFullDuplex()) {
|
||||||
if(fullDuplex) {
|
|
||||||
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 +319,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) {
|
||||||
@ -325,10 +338,35 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MutexIF* SpiComIF::getMutex() {
|
MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) {
|
||||||
|
if(timeoutType != nullptr) {
|
||||||
|
*timeoutType = this->timeoutType;
|
||||||
|
}
|
||||||
|
if(timeoutMs != nullptr) {
|
||||||
|
*timeoutMs = this->timeoutMs;
|
||||||
|
}
|
||||||
return spiMutex;
|
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) {
|
ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
|
||||||
if(buffer == nullptr) {
|
if(buffer == nullptr) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
@ -343,6 +381,10 @@ ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GpioIF* SpiComIF::getGpioInterface() {
|
||||||
|
return gpioComIF;
|
||||||
|
}
|
||||||
|
|
||||||
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) {
|
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) {
|
||||||
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
|
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
|
||||||
if(retval != 0) {
|
if(retval != 0) {
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#define LINUX_SPI_SPICOMIF_H_
|
#define LINUX_SPI_SPICOMIF_H_
|
||||||
|
|
||||||
#include "spiDefinitions.h"
|
#include "spiDefinitions.h"
|
||||||
#include <returnvalues/classIds.h>
|
#include "returnvalues/classIds.h"
|
||||||
#include <fsfw_hal/common/gpio/GpioIF.h>
|
#include "../../common/gpio/GpioIF.h"
|
||||||
|
|
||||||
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||||
#include <fsfw/objectmanager/SystemObject.h>
|
#include <fsfw/objectmanager/SystemObject.h>
|
||||||
@ -11,10 +11,13 @@
|
|||||||
#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
|
||||||
* Right now, only full-duplex SPI is supported.
|
* Right now, only full-duplex SPI is supported. Most device specific transfer properties
|
||||||
|
* are contained in the SPI cookie.
|
||||||
* @author R. Mueller
|
* @author R. Mueller
|
||||||
*/
|
*/
|
||||||
class SpiComIF: public DeviceCommunicationIF, public SystemObject {
|
class SpiComIF: public DeviceCommunicationIF, public SystemObject {
|
||||||
@ -39,11 +42,28 @@ 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.
|
||||||
*/
|
*/
|
||||||
MutexIF* getMutex();
|
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 functions like a 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:
|
private:
|
||||||
|
|
||||||
struct SpiInstance {
|
struct SpiInstance {
|
||||||
@ -61,9 +81,9 @@ 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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* LINUX_SPI_SPICOMIF_H_ */
|
#endif /* LINUX_SPI_SPICOMIF_H_ */
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#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,
|
||||||
@ -11,6 +12,25 @@ SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxS
|
|||||||
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,
|
void SpiCookie::getSpiParameters(spi::SpiModes& spiMode, uint32_t& spiSpeed,
|
||||||
UncommonParameters* parameters) const {
|
UncommonParameters* parameters) const {
|
||||||
spiMode = this->spiMode;
|
spiMode = this->spiMode;
|
||||||
@ -78,6 +98,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 +132,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;
|
||||||
|
}
|
||||||
|
@ -2,13 +2,25 @@
|
|||||||
#define LINUX_SPI_SPICOOKIE_H_
|
#define LINUX_SPI_SPICOOKIE_H_
|
||||||
|
|
||||||
#include "spiDefinitions.h"
|
#include "spiDefinitions.h"
|
||||||
|
#include "../../common/gpio/gpioDefinitions.h"
|
||||||
|
|
||||||
#include <fsfw/devicehandlers/CookieIF.h>
|
#include <fsfw/devicehandlers/CookieIF.h>
|
||||||
#include <fsfw_hal/common/gpio/gpioDefinitions.h>
|
|
||||||
#include <linux/spi/spidev.h>
|
#include <linux/spi/spidev.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This cookie class is passed to the SPI communication interface
|
||||||
|
* @details
|
||||||
|
* This cookie contains device specific properties like speed and SPI mode or the SPI transfer
|
||||||
|
* struct required by the Linux SPI driver. It also contains a handle to a GPIO interface
|
||||||
|
* to perform slave select switching when necessary.
|
||||||
|
*
|
||||||
|
* The user can specify gpio::NO_GPIO as the GPIO ID or use a custom send callback to meet
|
||||||
|
* special requirements like expander slave select switching (e.g. GPIO or I2C expander)
|
||||||
|
* or special timing related requirements.
|
||||||
|
*/
|
||||||
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 +31,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 +40,41 @@ 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, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
|
||||||
|
spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback,
|
||||||
|
void *args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the callback function
|
||||||
|
* @param callback
|
||||||
|
* @param 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the SPI to callback mode and assigns the user supplied callback and an argument
|
||||||
|
* passed to the callback.
|
||||||
|
* @param callback
|
||||||
|
* @param args
|
||||||
|
*/
|
||||||
|
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 +136,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;
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
#ifndef LINUX_SPI_SPIDEFINITONS_H_
|
#ifndef LINUX_SPI_SPIDEFINITONS_H_
|
||||||
#define 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>
|
#include <cstdint>
|
||||||
|
|
||||||
|
class SpiCookie;
|
||||||
|
class SpiComIF;
|
||||||
|
|
||||||
namespace spi {
|
namespace spi {
|
||||||
|
|
||||||
enum SpiModes: uint8_t {
|
enum SpiModes: uint8_t {
|
||||||
@ -12,6 +20,15 @@ enum SpiModes: uint8_t {
|
|||||||
MODE_3
|
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_ */
|
#endif /* LINUX_SPI_SPIDEFINITONS_H_ */
|
||||||
|
8
linux/uart/CMakeLists.txt
Normal file
8
linux/uart/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
target_sources(${TARGET_NAME} PUBLIC
|
||||||
|
UartComIF.cpp
|
||||||
|
UartCookie.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
370
linux/uart/UartComIF.cpp
Normal file
370
linux/uart/UartComIF.cpp
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
#include "UartComIF.h"
|
||||||
|
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
UartComIF::UartComIF(object_id_t objectId): SystemObject(objectId){
|
||||||
|
}
|
||||||
|
|
||||||
|
UartComIF::~UartComIF() {}
|
||||||
|
|
||||||
|
ReturnValue_t UartComIF::initializeInterface(CookieIF * cookie) {
|
||||||
|
|
||||||
|
std::string deviceFile;
|
||||||
|
UartDeviceMapIter uartDeviceMapIter;
|
||||||
|
|
||||||
|
if(cookie == nullptr) {
|
||||||
|
return NULLPOINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||||
|
if (uartCookie == nullptr) {
|
||||||
|
sif::error << "UartComIF::initializeInterface: Invalid UART Cookie!" << std::endl;
|
||||||
|
return NULLPOINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceFile = uartCookie->getDeviceFile();
|
||||||
|
|
||||||
|
uartDeviceMapIter = uartDeviceMap.find(deviceFile);
|
||||||
|
if(uartDeviceMapIter == uartDeviceMap.end()) {
|
||||||
|
int fileDescriptor = configureUartPort(uartCookie);
|
||||||
|
if (fileDescriptor < 0) {
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
size_t maxReplyLen = uartCookie->getMaxReplyLen();
|
||||||
|
UartElements_t uartElements = {fileDescriptor, std::vector<uint8_t>(maxReplyLen), 0};
|
||||||
|
std::pair status = uartDeviceMap.emplace(deviceFile, uartElements);
|
||||||
|
if (status.second == false) {
|
||||||
|
sif::debug << "UartComIF::initializeInterface: Failed to insert device " << deviceFile
|
||||||
|
<< "to Uart device map" << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sif::debug << "UartComIF::initializeInterface: Uart device " << deviceFile << "already in "
|
||||||
|
<< "use" << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UartComIF::configureUartPort(UartCookie* uartCookie) {
|
||||||
|
|
||||||
|
struct termios options;
|
||||||
|
|
||||||
|
std::string deviceFile = uartCookie->getDeviceFile();
|
||||||
|
int fd = open(deviceFile.c_str(), O_RDWR);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
sif::debug << "UartComIF::configureUartPort: Failed to open uart " << deviceFile << "with"
|
||||||
|
<< " error code " << errno << strerror(errno) << std::endl;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in existing settings */
|
||||||
|
if(tcgetattr(fd, &options) != 0) {
|
||||||
|
sif::debug << "UartComIF::configureUartPort: Error " << errno << "from tcgetattr: "
|
||||||
|
<< strerror(errno) << std::endl;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
setParityOptions(&options, uartCookie);
|
||||||
|
setStopBitOptions(&options, uartCookie);
|
||||||
|
setDatasizeOptions(&options, uartCookie);
|
||||||
|
setFixedOptions(&options);
|
||||||
|
|
||||||
|
/* Sets uart to non-blocking mode. Read returns immediately when there are no data available */
|
||||||
|
options.c_cc[VTIME] = 0;
|
||||||
|
options.c_cc[VMIN] = 0;
|
||||||
|
|
||||||
|
configureBaudrate(&options, uartCookie);
|
||||||
|
|
||||||
|
/* Save option settings */
|
||||||
|
if (tcsetattr(fd, TCSANOW, &options) != 0) {
|
||||||
|
sif::debug << "UartComIF::configureUartPort: Failed to set options with error " << errno
|
||||||
|
<< ": " << strerror(errno);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartComIF::setParityOptions(struct termios* options, UartCookie* uartCookie) {
|
||||||
|
/* Clear parity bit */
|
||||||
|
options->c_cflag &= ~PARENB;
|
||||||
|
switch (uartCookie->getParity()) {
|
||||||
|
case Parity::EVEN:
|
||||||
|
options->c_cflag |= PARENB;
|
||||||
|
options->c_cflag &= ~PARODD;
|
||||||
|
break;
|
||||||
|
case Parity::ODD:
|
||||||
|
options->c_cflag |= PARENB;
|
||||||
|
options->c_cflag |= PARODD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartComIF::setStopBitOptions(struct termios* options, UartCookie* uartCookie) {
|
||||||
|
/* Clear stop field. Sets stop bit to one bit */
|
||||||
|
options->c_cflag &= ~CSTOPB;
|
||||||
|
switch (uartCookie->getStopBits()) {
|
||||||
|
case StopBits::TWO_STOP_BITS:
|
||||||
|
options->c_cflag |= CSTOPB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartComIF::setDatasizeOptions(struct termios* options, UartCookie* uartCookie) {
|
||||||
|
/* Clear size bits */
|
||||||
|
options->c_cflag &= ~CSIZE;
|
||||||
|
switch (uartCookie->getBitsPerWord()) {
|
||||||
|
case 5:
|
||||||
|
options->c_cflag |= CS5;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
options->c_cflag |= CS6;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
options->c_cflag |= CS7;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
options->c_cflag |= CS8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sif::debug << "UartComIF::setDatasizeOptions: Invalid size specified" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartComIF::setFixedOptions(struct termios* options) {
|
||||||
|
/* Disable RTS/CTS hardware flow control */
|
||||||
|
options->c_cflag &= ~CRTSCTS;
|
||||||
|
/* Turn on READ & ignore ctrl lines (CLOCAL = 1) */
|
||||||
|
options->c_cflag |= CREAD | CLOCAL;
|
||||||
|
/* Disable canonical mode */
|
||||||
|
options->c_lflag &= ~ICANON;
|
||||||
|
/* Disable echo */
|
||||||
|
options->c_lflag &= ~ECHO;
|
||||||
|
/* Disable erasure */
|
||||||
|
options->c_lflag &= ~ECHOE;
|
||||||
|
/* Disable new-line echo */
|
||||||
|
options->c_lflag &= ~ECHONL;
|
||||||
|
/* Disable interpretation of INTR, QUIT and SUSP */
|
||||||
|
options->c_lflag &= ~ISIG;
|
||||||
|
/* Turn off s/w flow ctrl */
|
||||||
|
options->c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||||
|
/* Disable any special handling of received bytes */
|
||||||
|
options->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
|
||||||
|
/* Prevent special interpretation of output bytes (e.g. newline chars) */
|
||||||
|
options->c_oflag &= ~OPOST;
|
||||||
|
/* Prevent conversion of newline to carriage return/line feed */
|
||||||
|
options->c_oflag &= ~ONLCR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCookie) {
|
||||||
|
switch (uartCookie->getBaudrate()) {
|
||||||
|
case 50:
|
||||||
|
cfsetispeed(options, B50);
|
||||||
|
cfsetospeed(options, B50);
|
||||||
|
break;
|
||||||
|
case 75:
|
||||||
|
cfsetispeed(options, B75);
|
||||||
|
cfsetospeed(options, B75);
|
||||||
|
break;
|
||||||
|
case 110:
|
||||||
|
cfsetispeed(options, B110);
|
||||||
|
cfsetospeed(options, B110);
|
||||||
|
break;
|
||||||
|
case 134:
|
||||||
|
cfsetispeed(options, B134);
|
||||||
|
cfsetospeed(options, B134);
|
||||||
|
break;
|
||||||
|
case 150:
|
||||||
|
cfsetispeed(options, B150);
|
||||||
|
cfsetospeed(options, B150);
|
||||||
|
break;
|
||||||
|
case 200:
|
||||||
|
cfsetispeed(options, B200);
|
||||||
|
cfsetospeed(options, B200);
|
||||||
|
break;
|
||||||
|
case 300:
|
||||||
|
cfsetispeed(options, B300);
|
||||||
|
cfsetospeed(options, B300);
|
||||||
|
break;
|
||||||
|
case 600:
|
||||||
|
cfsetispeed(options, B600);
|
||||||
|
cfsetospeed(options, B600);
|
||||||
|
break;
|
||||||
|
case 1200:
|
||||||
|
cfsetispeed(options, B1200);
|
||||||
|
cfsetospeed(options, B1200);
|
||||||
|
break;
|
||||||
|
case 1800:
|
||||||
|
cfsetispeed(options, B1800);
|
||||||
|
cfsetospeed(options, B1800);
|
||||||
|
break;
|
||||||
|
case 2400:
|
||||||
|
cfsetispeed(options, B2400);
|
||||||
|
cfsetospeed(options, B2400);
|
||||||
|
break;
|
||||||
|
case 4800:
|
||||||
|
cfsetispeed(options, B4800);
|
||||||
|
cfsetospeed(options, B4800);
|
||||||
|
break;
|
||||||
|
case 9600:
|
||||||
|
cfsetispeed(options, B9600);
|
||||||
|
cfsetospeed(options, B9600);
|
||||||
|
break;
|
||||||
|
case 19200:
|
||||||
|
cfsetispeed(options, B19200);
|
||||||
|
cfsetospeed(options, B19200);
|
||||||
|
break;
|
||||||
|
case 38400:
|
||||||
|
cfsetispeed(options, B38400);
|
||||||
|
cfsetospeed(options, B38400);
|
||||||
|
break;
|
||||||
|
case 57600:
|
||||||
|
cfsetispeed(options, B57600);
|
||||||
|
cfsetospeed(options, B57600);
|
||||||
|
break;
|
||||||
|
case 115200:
|
||||||
|
cfsetispeed(options, B115200);
|
||||||
|
cfsetospeed(options, B115200);
|
||||||
|
break;
|
||||||
|
case 230400:
|
||||||
|
cfsetispeed(options, B230400);
|
||||||
|
cfsetospeed(options, B230400);
|
||||||
|
break;
|
||||||
|
case 460800:
|
||||||
|
cfsetispeed(options, B460800);
|
||||||
|
cfsetospeed(options, B460800);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UartComIF::sendMessage(CookieIF *cookie,
|
||||||
|
const uint8_t *sendData, size_t sendLen) {
|
||||||
|
|
||||||
|
int fd = 0;
|
||||||
|
std::string deviceFile;
|
||||||
|
UartDeviceMapIter uartDeviceMapIter;
|
||||||
|
|
||||||
|
if(sendData == nullptr) {
|
||||||
|
sif::debug << "UartComIF::sendMessage: Send Data is nullptr" << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sendLen == 0) {
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||||
|
if(uartCookie == nullptr) {
|
||||||
|
sif::debug << "UartComIF::sendMessasge: Invalid Uart Cookie!" << std::endl;
|
||||||
|
return NULLPOINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceFile = uartCookie->getDeviceFile();
|
||||||
|
uartDeviceMapIter = uartDeviceMap.find(deviceFile);
|
||||||
|
if (uartDeviceMapIter == uartDeviceMap.end()) {
|
||||||
|
sif::debug << "UartComIF::sendMessage: Device file " << deviceFile << "not in uart map"
|
||||||
|
<< std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = uartDeviceMapIter->second.fileDescriptor;
|
||||||
|
|
||||||
|
if (write(fd, sendData, sendLen) != (int)sendLen) {
|
||||||
|
sif::error << "UartComIF::sendMessage: Failed to send data with error code " << errno
|
||||||
|
<< ": Error description: " << strerror(errno) << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UartComIF::getSendSuccess(CookieIF *cookie) {
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UartComIF::requestReceiveMessage(CookieIF *cookie,
|
||||||
|
size_t requestLen) {
|
||||||
|
|
||||||
|
int fd = 0;
|
||||||
|
std::string deviceFile;
|
||||||
|
UartDeviceMapIter uartDeviceMapIter;
|
||||||
|
uint8_t* bufferPtr;
|
||||||
|
|
||||||
|
if(requestLen == 0) {
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||||
|
if(uartCookie == nullptr) {
|
||||||
|
sif::debug << "UartComIF::requestReceiveMessage: Invalid Uart Cookie!" << std::endl;
|
||||||
|
return NULLPOINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceFile = uartCookie->getDeviceFile();
|
||||||
|
uartDeviceMapIter = uartDeviceMap.find(deviceFile);
|
||||||
|
if (uartDeviceMapIter == uartDeviceMap.end()) {
|
||||||
|
sif::debug << "UartComIF::requestReceiveMessage: Device file " << deviceFile
|
||||||
|
<< " not in uart map" << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = uartDeviceMapIter->second.fileDescriptor;
|
||||||
|
bufferPtr = uartDeviceMapIter->second.replyBuffer.data();
|
||||||
|
int bytesRead = read(fd, bufferPtr, requestLen);
|
||||||
|
if (bytesRead != static_cast<int>(requestLen)) {
|
||||||
|
sif::debug << "UartComIF::requestReceiveMessage: Only read " << bytesRead
|
||||||
|
<< " of " << requestLen << " bytes" << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uartDeviceMapIter->second.replyLen = bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie,
|
||||||
|
uint8_t **buffer, size_t* size) {
|
||||||
|
|
||||||
|
std::string deviceFile;
|
||||||
|
UartDeviceMapIter uartDeviceMapIter;
|
||||||
|
|
||||||
|
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||||
|
if(uartCookie == nullptr) {
|
||||||
|
sif::debug << "UartComIF::readReceivedMessage: Invalid uart cookie!" << std::endl;
|
||||||
|
return NULLPOINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceFile = uartCookie->getDeviceFile();
|
||||||
|
uartDeviceMapIter = uartDeviceMap.find(deviceFile);
|
||||||
|
if (uartDeviceMapIter == uartDeviceMap.end()) {
|
||||||
|
sif::debug << "UartComIF::readReceivedMessage: Device file " << deviceFile
|
||||||
|
<< " not in uart map" << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buffer = uartDeviceMapIter->second.replyBuffer.data();
|
||||||
|
*size = uartDeviceMapIter->second.replyLen;
|
||||||
|
|
||||||
|
/* Length is reset to 0 to prevent reading the same data twice */
|
||||||
|
uartDeviceMapIter->second.replyLen = 0;
|
||||||
|
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
94
linux/uart/UartComIF.h
Normal file
94
linux/uart/UartComIF.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#ifndef BSP_Q7S_COMIF_UARTCOMIF_H_
|
||||||
|
#define BSP_Q7S_COMIF_UARTCOMIF_H_
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/SystemObject.h>
|
||||||
|
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "UartCookie.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This is the communication interface to access serial ports on linux based operating
|
||||||
|
* systems.
|
||||||
|
*
|
||||||
|
* @details The implementation follows the instructions from https://blog.mbedded.ninja/programming/
|
||||||
|
* operating-systems/linux/linux-serial-ports-using-c-cpp/#disabling-canonical-mode
|
||||||
|
*
|
||||||
|
* @author J. Meier
|
||||||
|
*/
|
||||||
|
class UartComIF: public DeviceCommunicationIF, public SystemObject {
|
||||||
|
public:
|
||||||
|
UartComIF(object_id_t objectId);
|
||||||
|
|
||||||
|
virtual ~UartComIF();
|
||||||
|
|
||||||
|
ReturnValue_t initializeInterface(CookieIF * cookie) override;
|
||||||
|
ReturnValue_t sendMessage(CookieIF *cookie,const uint8_t *sendData,
|
||||||
|
size_t sendLen) override;
|
||||||
|
ReturnValue_t getSendSuccess(CookieIF *cookie) override;
|
||||||
|
ReturnValue_t requestReceiveMessage(CookieIF *cookie,
|
||||||
|
size_t requestLen) override;
|
||||||
|
ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
|
||||||
|
size_t *size) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
using UartDeviceFile_t = std::string;
|
||||||
|
|
||||||
|
typedef struct UartElements {
|
||||||
|
int fileDescriptor;
|
||||||
|
std::vector<uint8_t> replyBuffer;
|
||||||
|
/** Number of bytes read will be written to this variable */
|
||||||
|
size_t replyLen;
|
||||||
|
} UartElements_t;
|
||||||
|
|
||||||
|
using UartDeviceMap = std::unordered_map<UartDeviceFile_t, UartElements_t>;
|
||||||
|
using UartDeviceMapIter = UartDeviceMap::iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The uart devie map stores informations of initialized uart ports.
|
||||||
|
*/
|
||||||
|
UartDeviceMap uartDeviceMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function opens and configures a uart device by using the information stored
|
||||||
|
* in the uart cookie.
|
||||||
|
* @param uartCookie Pointer to uart cookie with information about the uart. Contains the
|
||||||
|
* uart device file, baudrate, parity, stopbits etc.
|
||||||
|
* @return The file descriptor of the configured uart.
|
||||||
|
*/
|
||||||
|
int configureUartPort(UartCookie* uartCookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function adds the parity settings to the termios options struct.
|
||||||
|
*
|
||||||
|
* @param options Pointer to termios options struct which will be modified to enable or disable
|
||||||
|
* parity checking.
|
||||||
|
* @param uartCookie Pointer to uart cookie containing the information about the desired
|
||||||
|
* parity settings.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void setParityOptions(struct termios* options, UartCookie* uartCookie);
|
||||||
|
|
||||||
|
void setStopBitOptions(struct termios* options, UartCookie* uartCookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function sets options which are not configurable by the uartCookie.
|
||||||
|
*/
|
||||||
|
void setFixedOptions(struct termios* options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief With this function the datasize settings are added to the termios options struct.
|
||||||
|
*/
|
||||||
|
void setDatasizeOptions(struct termios* options, UartCookie* uartCookie);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This functions adds the baudrate specified in the uartCookie to the termios options
|
||||||
|
* struct.
|
||||||
|
*/
|
||||||
|
void configureBaudrate(struct termios* options, UartCookie* uartCookie);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* BSP_Q7S_COMIF_UARTCOMIF_H_ */
|
63
linux/uart/UartCookie.cpp
Normal file
63
linux/uart/UartCookie.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include "UartCookie.h"
|
||||||
|
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
|
|
||||||
|
UartCookie::UartCookie(std::string deviceFile, uint32_t baudrate, size_t maxReplyLen) :
|
||||||
|
deviceFile(deviceFile), baudrate(baudrate), maxReplyLen(maxReplyLen) {
|
||||||
|
}
|
||||||
|
|
||||||
|
UartCookie::~UartCookie() {}
|
||||||
|
|
||||||
|
uint32_t UartCookie::getBaudrate() const {
|
||||||
|
return baudrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UartCookie::getMaxReplyLen() const {
|
||||||
|
return maxReplyLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UartCookie::getDeviceFile() const {
|
||||||
|
return deviceFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartCookie::setParityOdd() {
|
||||||
|
parity = Parity::ODD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartCookie::setParityEven() {
|
||||||
|
parity = Parity::EVEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parity UartCookie::getParity() const {
|
||||||
|
return parity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartCookie::setBitsPerWord(uint8_t bitsPerWord_) {
|
||||||
|
switch(bitsPerWord_) {
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sif::debug << "UartCookie::setBitsPerWord: Invalid bits per word specified" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bitsPerWord = bitsPerWord_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t UartCookie::getBitsPerWord() const {
|
||||||
|
return bitsPerWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
StopBits UartCookie::getStopBits() const {
|
||||||
|
return stopBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartCookie::setTwoStopBits() {
|
||||||
|
stopBits = StopBits::TWO_STOP_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartCookie::setOneStopBit() {
|
||||||
|
stopBits = StopBits::ONE_STOP_BIT;
|
||||||
|
}
|
81
linux/uart/UartCookie.h
Normal file
81
linux/uart/UartCookie.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#ifndef SAM9G20_COMIF_COOKIES_UART_COOKIE_H_
|
||||||
|
#define SAM9G20_COMIF_COOKIES_UART_COOKIE_H_
|
||||||
|
|
||||||
|
#include <fsfw/devicehandlers/CookieIF.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
enum class Parity {
|
||||||
|
NONE,
|
||||||
|
EVEN,
|
||||||
|
ODD
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class StopBits {
|
||||||
|
ONE_STOP_BIT,
|
||||||
|
TWO_STOP_BITS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cookie for the UartComIF. There are many options available to configure the uart driver.
|
||||||
|
* The constructor only requests for common options like the baudrate. Other options can
|
||||||
|
* be set by member functions.
|
||||||
|
*
|
||||||
|
* @author J. Meier
|
||||||
|
*/
|
||||||
|
class UartCookie: public CookieIF {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor for the uart cookie.
|
||||||
|
* @param deviceFile The device file specifying the uart to use. E.g. "/dev/ttyPS1".
|
||||||
|
* @param baudrate The baudrate to use for input and output. Possible Baudrates are: 50,
|
||||||
|
* 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, B19200,
|
||||||
|
* 38400, 57600, 115200, 230400, 460800
|
||||||
|
* @param maxReplyLen The maximum size an object using this cookie expects.
|
||||||
|
*
|
||||||
|
* @details Default configuration: No parity
|
||||||
|
* 8 databits (number of bits transfered with one uart frame)
|
||||||
|
* One stop bit
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
UartCookie(std::string deviceFile, uint32_t baudrate, size_t maxReplyLen);
|
||||||
|
|
||||||
|
virtual ~UartCookie();
|
||||||
|
|
||||||
|
uint32_t getBaudrate() const;
|
||||||
|
size_t getMaxReplyLen() const;
|
||||||
|
std::string getDeviceFile() const;
|
||||||
|
Parity getParity() const;
|
||||||
|
uint8_t getBitsPerWord() const;
|
||||||
|
StopBits getStopBits() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions two enable parity checking.
|
||||||
|
*/
|
||||||
|
void setParityOdd();
|
||||||
|
void setParityEven();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function two set number of bits per UART frame.
|
||||||
|
*/
|
||||||
|
void setBitsPerWord(uint8_t bitsPerWord_);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to specify the number of stopbits.
|
||||||
|
*/
|
||||||
|
void setTwoStopBits();
|
||||||
|
void setOneStopBit();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string deviceFile;
|
||||||
|
uint32_t baudrate;
|
||||||
|
size_t maxReplyLen = 0;
|
||||||
|
Parity parity = Parity::NONE;
|
||||||
|
uint8_t bitsPerWord = 8;
|
||||||
|
StopBits stopBits = StopBits::ONE_STOP_BIT;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user