From 9203a30bcf5b3305ad30259c3fe7eca2194c5592 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 23 May 2021 21:34:59 +0200 Subject: [PATCH 01/15] added callback functionality to spi --- linux/spi/SpiComIF.cpp | 143 ++++++++++++++++++++----------------- linux/spi/SpiComIF.h | 4 ++ linux/spi/SpiCookie.cpp | 40 +++++++++-- linux/spi/SpiCookie.h | 39 +++++++++- linux/spi/spiDefinitions.h | 10 +++ 5 files changed, 166 insertions(+), 70 deletions(-) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index 9225adb..3cc81f8 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -21,7 +21,7 @@ #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 @@ -158,86 +158,96 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s return DeviceCommunicationIF::TOO_MUCH_DATA; } + if(spiCookie->getComIfMode() == spi::SpiComIfModes::REGULAR) { + /* Prepare transfer */ + int fileDescriptor = 0; + std::string device = spiCookie->getSpiDevice(); + UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, + "SpiComIF::sendMessage: "); + if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { + return OPENING_FILE_FAILED; + } + spi::SpiModes spiMode = spi::SpiModes::MODE_0; + uint32_t spiSpeed = 0; + spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); + setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); + spiCookie->assignWriteBuffer(sendData); + spiCookie->assignTransferSize(sendLen); - /* Prepare transfer */ - int fileDescriptor = 0; - std::string device = spiCookie->getSpiDevice(); - UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, - "SpiComIF::sendMessage: "); - if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { - return OPENING_FILE_FAILED; - } - spi::SpiModes spiMode = spi::SpiModes::MODE_0; - uint32_t spiSpeed = 0; - spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); - setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); - spiCookie->assignWriteBuffer(sendData); - spiCookie->assignTransferSize(sendLen); + bool fullDuplex = spiCookie->isFullDuplex(); + gpioId_t gpioId = spiCookie->getChipSelectPin(); - 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) { + /* 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; + sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl; #endif - return result; + return result; + } + gpioComIF->pullLow(gpioId); } - gpioComIF->pullLow(gpioId); - } - /* 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; - } + /* 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; + } #if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1 - size_t dataLen = spiCookie->getTransferStructHandle()->len; - uint8_t* dataPtr = reinterpret_cast(spiCookie->getTransferStructHandle()->tx_buf); + size_t dataLen = spiCookie->getTransferStructHandle()->len; + uint8_t* dataPtr = reinterpret_cast(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; + 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"); + 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(spiCookie->getTransferStructHandle()->rx_buf); - arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); + dataPtr = reinterpret_cast(spiCookie->getTransferStructHandle()->rx_buf); + arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); #endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */ - } - else { - /* We write with a blocking half-duplex transfer here */ - if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { + } + else { + /* We write with a blocking half-duplex transfer here */ + if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << - std::endl; + sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << + std::endl; #else - sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n"); + sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n"); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ - result = HALF_DUPLEX_TRANSFER_FAILED; + result = HALF_DUPLEX_TRANSFER_FAILED; + } + } + + if(gpioId != gpio::NO_GPIO) { + gpioComIF->pullHigh(gpioId); + result = spiMutex->unlockMutex(); + if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl; +#endif + return result; + } + } + } + else if(spiCookie->getComIfMode() == spi::SpiComIfModes::CALLBACK) { + spi::send_callback_function_t sendFunc = nullptr; + void* funcArgs = nullptr; + spiCookie->getCallback(&sendFunc, &funcArgs); + if(sendFunc != nullptr) { + // sendFunc() } } - if(gpioId != gpio::NO_GPIO) { - gpioComIF->pullHigh(gpioId); - result = spiMutex->unlockMutex(); - if (result != RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl; -#endif - return result; - } - } return result; } @@ -246,7 +256,6 @@ 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(cookie); if(spiCookie == nullptr) { return NULLPOINTER; @@ -257,6 +266,12 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe 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, @@ -306,7 +321,7 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe } } - return HasReturnvaluesIF::RETURN_OK; + return result; } ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) { diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index 9228994..ddb7761 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -11,6 +11,8 @@ #include #include +class SpiCookie; + /** * @brief Encapsulates access to linux SPI driver for FSFW objects * @details @@ -39,6 +41,7 @@ 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. @@ -61,6 +64,7 @@ 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); diff --git a/linux/spi/SpiCookie.cpp b/linux/spi/SpiCookie.cpp index 9111768..07acf28 100644 --- a/linux/spi/SpiCookie.cpp +++ b/linux/spi/SpiCookie.cpp @@ -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, std::string spiDev, const size_t maxSize, + spi::send_callback_function_t callback, void *args): + SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, gpio::NO_GPIO, spiDev, maxSize, + spi::SpiModes::MODE_0, 0, callback, args) { +} + +SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect, + std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed, + spi::send_callback_function_t callback, void* args): spiAddress(spiAddress), + chipSelectPin(chipSelect), spiDevice(spiDev), comIfMode(comIfMode), + maxSize(maxSize), spiMode(spiMode), spiSpeed(spiSpeed), sendCallback(callback), + callbackArgs(args) { +} + +spi::SpiComIfModes SpiCookie::getComIfMode() const { + return this->comIfMode; } void SpiCookie::getSpiParameters(spi::SpiModes& spiMode, uint32_t& spiSpeed, @@ -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; +} diff --git a/linux/spi/SpiCookie.h b/linux/spi/SpiCookie.h index aff4d77..a686249 100644 --- a/linux/spi/SpiCookie.h +++ b/linux/spi/SpiCookie.h @@ -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, std::string spiDev, const size_t maxSize, + spi::send_callback_function_t callback, void *args); + + void getCallback(spi::send_callback_function_t* callback, void** args); + address_t getSpiAddress() const; 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; }; diff --git a/linux/spi/spiDefinitions.h b/linux/spi/spiDefinitions.h index e8c4814..c131038 100644 --- a/linux/spi/spiDefinitions.h +++ b/linux/spi/spiDefinitions.h @@ -1,6 +1,8 @@ #ifndef LINUX_SPI_SPIDEFINITONS_H_ #define LINUX_SPI_SPIDEFINITONS_H_ +#include "fsfw/returnvalues/HasReturnvaluesIF.h" + #include namespace spi { @@ -12,6 +14,14 @@ enum SpiModes: uint8_t { MODE_3 }; +enum SpiComIfModes { + REGULAR, + CALLBACK +}; + + +using send_callback_function_t = ReturnValue_t (*) (uint8_t** replyData, void* args); + } #endif /* LINUX_SPI_SPIDEFINITONS_H_ */ From 2fe1a6683606eddb76aa810f88e5cf5d8cea94e5 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 24 May 2021 00:13:59 +0200 Subject: [PATCH 02/15] added callback function --- linux/spi/SpiComIF.cpp | 166 +++++++++++++++++++------------------ linux/spi/SpiComIF.h | 1 + linux/spi/SpiCookie.cpp | 4 +- linux/spi/SpiCookie.h | 2 +- linux/spi/spiDefinitions.h | 7 +- 5 files changed, 95 insertions(+), 85 deletions(-) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index 3cc81f8..494c112 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -138,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(cookie); ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - int retval = 0; if(spiCookie == nullptr) { return NULLPOINTER; @@ -159,95 +158,100 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s } if(spiCookie->getComIfMode() == spi::SpiComIfModes::REGULAR) { - /* Prepare transfer */ - int fileDescriptor = 0; - std::string device = spiCookie->getSpiDevice(); - UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, - "SpiComIF::sendMessage: "); - if(fileHelper.getOpenResult() != HasReturnvaluesIF::RETURN_OK) { - return OPENING_FILE_FAILED; - } - spi::SpiModes spiMode = spi::SpiModes::MODE_0; - uint32_t spiSpeed = 0; - spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); - setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); - spiCookie->assignWriteBuffer(sendData); - spiCookie->assignTransferSize(sendLen); - - 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) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl; -#endif - return result; - } - gpioComIF->pullLow(gpioId); - } - - /* 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; - } -#if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1 - size_t dataLen = spiCookie->getTransferStructHandle()->len; - uint8_t* dataPtr = reinterpret_cast(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(spiCookie->getTransferStructHandle()->rx_buf); - arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); -#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */ - } - else { - /* We write with a blocking half-duplex transfer here */ - if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { -#if FSFW_VERBOSE_LEVEL >= 1 -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << - std::endl; -#else - sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n"); -#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ -#endif /* FSFW_VERBOSE_LEVEL >= 1 */ - result = HALF_DUPLEX_TRANSFER_FAILED; - } - } - - if(gpioId != gpio::NO_GPIO) { - gpioComIF->pullHigh(gpioId); - result = spiMutex->unlockMutex(); - if (result != RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl; -#endif - return result; - } - } + 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) { - // sendFunc() + result = sendFunc(spiCookie, sendData, sendLen, funcArgs); + } + } + return result; +} + +ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const uint8_t *sendData, size_t sendLen) { + 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->assignTransferSize(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) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl; +#endif + return result; + } + gpioComIF->pullLow(gpioId); + } + + /* 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; + } +#if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1 + size_t dataLen = spiCookie->getTransferStructHandle()->len; + uint8_t* dataPtr = reinterpret_cast(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(spiCookie->getTransferStructHandle()->rx_buf); + arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); +#endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */ + } + else { + /* We write with a blocking half-duplex transfer here */ + if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { +#if FSFW_VERBOSE_LEVEL >= 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << + std::endl; +#else + sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_VERBOSE_LEVEL >= 1 */ + result = HALF_DUPLEX_TRANSFER_FAILED; } } + if(gpioId != gpio::NO_GPIO) { + gpioComIF->pullHigh(gpioId); + result = spiMutex->unlockMutex(); + if (result != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl; +#endif + return result; + } + } return result; } diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index ddb7761..5a99da4 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -64,6 +64,7 @@ private: SpiDeviceMap spiDeviceMap; + ReturnValue_t performRegularSendOperation(SpiCookie* spiCookie, const uint8_t *sendData, size_t sendLen); ReturnValue_t performHalfDuplexReception(SpiCookie* spiCookie); ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer); diff --git a/linux/spi/SpiCookie.cpp b/linux/spi/SpiCookie.cpp index 07acf28..1fff44e 100644 --- a/linux/spi/SpiCookie.cpp +++ b/linux/spi/SpiCookie.cpp @@ -12,9 +12,9 @@ SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxS SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) { } -SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize, +SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize, spi::send_callback_function_t callback, void *args): - SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, gpio::NO_GPIO, spiDev, maxSize, + SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize, spi::SpiModes::MODE_0, 0, callback, args) { } diff --git a/linux/spi/SpiCookie.h b/linux/spi/SpiCookie.h index a686249..604f6b2 100644 --- a/linux/spi/SpiCookie.h +++ b/linux/spi/SpiCookie.h @@ -31,7 +31,7 @@ public: * Use the callback mode of the SPI communication interface. The user can pass the callback * function here or by using the setter function #setCallbackMode */ - SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize, + SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize, spi::send_callback_function_t callback, void *args); void getCallback(spi::send_callback_function_t* callback, void** args); diff --git a/linux/spi/spiDefinitions.h b/linux/spi/spiDefinitions.h index c131038..ff6d66d 100644 --- a/linux/spi/spiDefinitions.h +++ b/linux/spi/spiDefinitions.h @@ -1,10 +1,15 @@ #ifndef LINUX_SPI_SPIDEFINITONS_H_ #define LINUX_SPI_SPIDEFINITONS_H_ +#include "../../common/gpio/gpioDefinitions.h" + #include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include #include +class SpiCookie; + namespace spi { enum SpiModes: uint8_t { @@ -20,7 +25,7 @@ enum SpiComIfModes { }; -using send_callback_function_t = ReturnValue_t (*) (uint8_t** replyData, void* args); +using send_callback_function_t = ReturnValue_t (*) (SpiCookie *cookie, const uint8_t *sendData, size_t sendLen, void* args); } From d801319c12713d08cbdbc571ee2a922ce2f0c851 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 24 May 2021 01:20:16 +0200 Subject: [PATCH 03/15] small fixes --- linux/spi/SpiCookie.cpp | 4 ++-- linux/spi/SpiCookie.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux/spi/SpiCookie.cpp b/linux/spi/SpiCookie.cpp index 1fff44e..a49c88a 100644 --- a/linux/spi/SpiCookie.cpp +++ b/linux/spi/SpiCookie.cpp @@ -13,9 +13,9 @@ SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxS } SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize, - spi::send_callback_function_t callback, void *args): + spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback, void *args): SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize, - spi::SpiModes::MODE_0, 0, callback, args) { + spiMode, spiSpeed, callback, args) { } SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect, diff --git a/linux/spi/SpiCookie.h b/linux/spi/SpiCookie.h index 604f6b2..d3da41b 100644 --- a/linux/spi/SpiCookie.h +++ b/linux/spi/SpiCookie.h @@ -32,7 +32,7 @@ public: * function here or by using the setter function #setCallbackMode */ SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize, - spi::send_callback_function_t callback, void *args); + spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback, void *args); void getCallback(spi::send_callback_function_t* callback, void** args); From f363d0fbd54fcc6b93f7475777543bbb1ad41ec6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 24 May 2021 19:11:01 +0200 Subject: [PATCH 04/15] com if passed to callback as well --- linux/spi/SpiComIF.cpp | 8 ++++---- linux/spi/spiDefinitions.h | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index 494c112..68ae6da 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -165,13 +165,14 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s void* funcArgs = nullptr; spiCookie->getCallback(&sendFunc, &funcArgs); if(sendFunc != nullptr) { - result = sendFunc(spiCookie, sendData, sendLen, funcArgs); + result = sendFunc(this, spiCookie, sendData, sendLen, funcArgs); } } return result; } -ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const uint8_t *sendData, size_t sendLen) { +ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const uint8_t *sendData, + size_t sendLen) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; int retval = 0; /* Prepare transfer */ @@ -265,8 +266,7 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF *cookie, size_t requestLe return NULLPOINTER; } - bool fullDuplex = spiCookie->isFullDuplex(); - if(fullDuplex) { + if(spiCookie->isFullDuplex()) { return HasReturnvaluesIF::RETURN_OK; } diff --git a/linux/spi/spiDefinitions.h b/linux/spi/spiDefinitions.h index ff6d66d..ee56f6d 100644 --- a/linux/spi/spiDefinitions.h +++ b/linux/spi/spiDefinitions.h @@ -9,6 +9,7 @@ #include class SpiCookie; +class SpiComIF; namespace spi { @@ -25,7 +26,8 @@ enum SpiComIfModes { }; -using send_callback_function_t = ReturnValue_t (*) (SpiCookie *cookie, const uint8_t *sendData, size_t sendLen, void* args); +using send_callback_function_t = ReturnValue_t (*) (SpiComIF* comIf, SpiCookie *cookie, + const uint8_t *sendData, size_t sendLen, void* args); } From 73a427d7e0605519aecfa53fa289b94e0143394f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 24 May 2021 20:33:43 +0200 Subject: [PATCH 05/15] function is public now --- linux/spi/SpiComIF.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index 5a99da4..8978b78 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -47,6 +47,17 @@ public: * the chip select must be driven from outside of the com if. */ MutexIF* getMutex(); + + /** + * 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); private: struct SpiInstance { @@ -64,7 +75,6 @@ private: SpiDeviceMap spiDeviceMap; - ReturnValue_t performRegularSendOperation(SpiCookie* spiCookie, const uint8_t *sendData, size_t sendLen); ReturnValue_t performHalfDuplexReception(SpiCookie* spiCookie); ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer); From bf8f3db41c5af69f0ff06effae307f4d3088da65 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 12:14:22 +0200 Subject: [PATCH 06/15] some tweaks to make callback usage more easy --- linux/spi/SpiComIF.cpp | 12 +++++++++++- linux/spi/SpiComIF.h | 8 ++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index 68ae6da..abc272f 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -344,7 +344,13 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, 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; } @@ -362,6 +368,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(&mode)); if(retval != 0) { diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index 8978b78..67d2991 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -46,7 +46,7 @@ public: * @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* 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 @@ -58,6 +58,10 @@ public: */ ReturnValue_t performRegularSendOperation(SpiCookie* spiCookie, const uint8_t *sendData, size_t sendLen); + + GpioIF* getGpioInterface(); + void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed); + private: struct SpiInstance { @@ -78,7 +82,7 @@ private: 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_ */ From 2893da047bc695fcb02b0f9567cef0366a37793a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 12:45:11 +0200 Subject: [PATCH 07/15] extracted wiretapping function --- linux/spi/SpiComIF.cpp | 33 ++++++++++++++++++++------------- linux/spi/SpiComIF.h | 1 + 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index abc272f..c98cde4 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -213,19 +213,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const result = FULL_DUPLEX_TRANSFER_FAILED; } #if FSFW_HAL_LINUX_SPI_WIRETAPPING == 1 - size_t dataLen = spiCookie->getTransferStructHandle()->len; - uint8_t* dataPtr = reinterpret_cast(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(spiCookie->getTransferStructHandle()->rx_buf); - arrayprinter::print(dataPtr, dataLen, OutputType::HEX, false); + performSpiWiretapping(spiCookie); #endif /* FSFW_LINUX_SPI_WIRETAPPING == 1 */ } else { @@ -354,6 +342,25 @@ MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeout return spiMutex; } +void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) { + if(spiCookie == nullptr) { + return; + } + size_t dataLen = spiCookie->getTransferStructHandle()->len; + uint8_t* dataPtr = reinterpret_cast(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(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; diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index 67d2991..87c72d8 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -61,6 +61,7 @@ public: GpioIF* getGpioInterface(); void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed); + void performSpiWiretapping(SpiCookie* spiCookie); private: From c2b4231802bcc25e1a2588ab4d12c8ecf64d2c47 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 13:52:39 +0200 Subject: [PATCH 08/15] default wiretapping off --- linux/spi/SpiComIF.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index c98cde4..f2dbce3 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -2,7 +2,7 @@ #include "SpiCookie.h" #include "../utility.h" #include "../UnixFileGuard.h" -#include +#include "FSFWConfig.h" #include #include @@ -17,7 +17,7 @@ /* 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), From 61d7c61852d19c91f798d6cfbe4a6fc694cda5df Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 14:01:42 +0200 Subject: [PATCH 09/15] resetting reply buffer for regular send --- linux/spi/SpiComIF.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index f2dbce3..cd76616 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -173,6 +173,12 @@ ReturnValue_t SpiComIF::sendMessage(CookieIF *cookie, const uint8_t *sendData, s 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 */ From 6487c88fc99ed8021b2d42cc1de9cba1b50d01d4 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 15:16:00 +0200 Subject: [PATCH 10/15] small bugfix --- linux/spi/SpiComIF.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index cd76616..fe0cdc9 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -175,7 +175,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie *spiCookie, const size_t sendLen) { address_t spiAddress = spiCookie->getSpiAddress(); auto iter = spiDeviceMap.find(spiAddress); - if(iter == spiDeviceMap.end()) { + if(iter != spiDeviceMap.end()) { spiCookie->assignReadBuffer(iter->second.replyBuffer.data()); } From 836296b3af78c4023971108630f8e043bc8f4338 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 15:18:05 +0200 Subject: [PATCH 11/15] indentation --- linux/spi/SpiComIF.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux/spi/SpiComIF.cpp b/linux/spi/SpiComIF.cpp index fe0cdc9..c39f397 100644 --- a/linux/spi/SpiComIF.cpp +++ b/linux/spi/SpiComIF.cpp @@ -20,8 +20,8 @@ #define FSFW_HAL_LINUX_SPI_WIRETAPPING 0 #endif -SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): SystemObject(objectId), -gpioComIF(gpioComIF) { +SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF): + SystemObject(objectId), gpioComIF(gpioComIF) { if(gpioComIF == nullptr) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 From 3c19e0f9ebcab9b291ba52142a15170db8e96748 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 15:33:50 +0200 Subject: [PATCH 12/15] some doc added --- linux/spi/SpiComIF.h | 2 +- linux/spi/SpiCookie.cpp | 13 +++++++------ linux/spi/SpiCookie.h | 25 ++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index 87c72d8..652a7f3 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -50,7 +50,7 @@ public: /** * 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. + * in functions like a user callback if special handling is only necessary for certain commands. * @param spiCookie * @param sendData * @param sendLen diff --git a/linux/spi/SpiCookie.cpp b/linux/spi/SpiCookie.cpp index a49c88a..15ba3e9 100644 --- a/linux/spi/SpiCookie.cpp +++ b/linux/spi/SpiCookie.cpp @@ -12,18 +12,19 @@ SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxS 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::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::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 { diff --git a/linux/spi/SpiCookie.h b/linux/spi/SpiCookie.h index d3da41b..1a2730a 100644 --- a/linux/spi/SpiCookie.h +++ b/linux/spi/SpiCookie.h @@ -6,6 +6,17 @@ #include #include +/** + * @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 { public: /** @@ -32,8 +43,14 @@ public: * 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); + 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; @@ -48,6 +65,12 @@ public: /** Enables changing the SPI mode at run-time */ 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); /** From c69f3144418529952f0dd994ba1383ca3c6dadd7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 15:34:44 +0200 Subject: [PATCH 13/15] additional doc --- linux/spi/SpiComIF.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index 652a7f3..4994097 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -16,7 +16,8 @@ class SpiCookie; /** * @brief Encapsulates access to linux SPI driver for FSFW objects * @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 */ class SpiComIF: public DeviceCommunicationIF, public SystemObject { From 9e5e6da6f89e410094a935ce399b79e55cf7208a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 15:35:53 +0200 Subject: [PATCH 14/15] include corrections --- linux/spi/SpiComIF.h | 5 ++--- linux/spi/SpiCookie.h | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/linux/spi/SpiComIF.h b/linux/spi/SpiComIF.h index 4994097..d1a583b 100644 --- a/linux/spi/SpiComIF.h +++ b/linux/spi/SpiComIF.h @@ -2,8 +2,8 @@ #define LINUX_SPI_SPICOMIF_H_ #include "spiDefinitions.h" -#include -#include +#include "returnvalues/classIds.h" +#include "../../common/gpio/GpioIF.h" #include #include @@ -84,7 +84,6 @@ private: ReturnValue_t performHalfDuplexReception(SpiCookie* spiCookie); ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer); - }; #endif /* LINUX_SPI_SPICOMIF_H_ */ diff --git a/linux/spi/SpiCookie.h b/linux/spi/SpiCookie.h index 1a2730a..174ca9e 100644 --- a/linux/spi/SpiCookie.h +++ b/linux/spi/SpiCookie.h @@ -2,8 +2,10 @@ #define LINUX_SPI_SPICOOKIE_H_ #include "spiDefinitions.h" +#include "../../common/gpio/gpioDefinitions.h" + #include -#include + #include /** From 4ba4e45789a9fc37c8ff45d09b7986ee1dbd53ca Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 25 May 2021 17:21:16 +0200 Subject: [PATCH 15/15] added uart com if --- linux/CMakeLists.txt | 3 +- linux/uart/CMakeLists.txt | 8 + linux/uart/UartComIF.cpp | 370 ++++++++++++++++++++++++++++++++++++++ linux/uart/UartComIF.h | 94 ++++++++++ linux/uart/UartCookie.cpp | 63 +++++++ linux/uart/UartCookie.h | 81 +++++++++ 6 files changed, 618 insertions(+), 1 deletion(-) create mode 100644 linux/uart/CMakeLists.txt create mode 100644 linux/uart/UartComIF.cpp create mode 100644 linux/uart/UartComIF.h create mode 100644 linux/uart/UartCookie.cpp create mode 100644 linux/uart/UartCookie.h diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 0d9082f..6c2ec77 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -9,4 +9,5 @@ target_sources(${LIB_FSFW_HAL_NAME} PRIVATE add_subdirectory(gpio) add_subdirectory(spi) -add_subdirectory(i2c) \ No newline at end of file +add_subdirectory(i2c) +add_subdirectory(uart) \ No newline at end of file diff --git a/linux/uart/CMakeLists.txt b/linux/uart/CMakeLists.txt new file mode 100644 index 0000000..7b503d0 --- /dev/null +++ b/linux/uart/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${TARGET_NAME} PUBLIC + UartComIF.cpp + UartCookie.cpp +) + + + + diff --git a/linux/uart/UartComIF.cpp b/linux/uart/UartComIF.cpp new file mode 100644 index 0000000..126e51d --- /dev/null +++ b/linux/uart/UartComIF.cpp @@ -0,0 +1,370 @@ +#include "UartComIF.h" + +#include + +#include +#include +#include +#include +#include + +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(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(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(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(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(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(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; +} diff --git a/linux/uart/UartComIF.h b/linux/uart/UartComIF.h new file mode 100644 index 0000000..9dd854d --- /dev/null +++ b/linux/uart/UartComIF.h @@ -0,0 +1,94 @@ +#ifndef BSP_Q7S_COMIF_UARTCOMIF_H_ +#define BSP_Q7S_COMIF_UARTCOMIF_H_ + +#include +#include + +#include +#include + +#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 replyBuffer; + /** Number of bytes read will be written to this variable */ + size_t replyLen; + } UartElements_t; + + using UartDeviceMap = std::unordered_map; + 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_ */ diff --git a/linux/uart/UartCookie.cpp b/linux/uart/UartCookie.cpp new file mode 100644 index 0000000..b814938 --- /dev/null +++ b/linux/uart/UartCookie.cpp @@ -0,0 +1,63 @@ +#include "UartCookie.h" + +#include + +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; +} diff --git a/linux/uart/UartCookie.h b/linux/uart/UartCookie.h new file mode 100644 index 0000000..5900471 --- /dev/null +++ b/linux/uart/UartCookie.h @@ -0,0 +1,81 @@ +#ifndef SAM9G20_COMIF_COOKIES_UART_COOKIE_H_ +#define SAM9G20_COMIF_COOKIES_UART_COOKIE_H_ + +#include +#include + +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