#ifndef LINUX_SPI_SPICOMIF_H_ #define LINUX_SPI_SPICOMIF_H_ #include #include #include "fsfw/FSFW.h" #include "fsfw/devicehandlers/DeviceCommunicationIF.h" #include "fsfw/objectmanager/SystemObject.h" #include "fsfw_hal/common/gpio/GpioIF.h" #include "returnvalues/classIds.h" #include "spiDefinitions.h" class SpiCookie; /** * @brief Encapsulates access to linux SPI driver for FSFW objects * @details * 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 { public: static constexpr uint8_t CLASS_ID = CLASS_ID::HAL_SPI; static constexpr ReturnValue_t OPENING_FILE_FAILED = HasReturnvaluesIF::makeReturnCode(CLASS_ID, 0); /* Full duplex (ioctl) transfer failure */ static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED = HasReturnvaluesIF::makeReturnCode(CLASS_ID, 1); /* Half duplex (read/write) transfer failure */ static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED = HasReturnvaluesIF::makeReturnCode(CLASS_ID, 2); SpiComIF(object_id_t objectId, std::string devname, GpioIF* gpioComIF); 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; /** * @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* getCsMutex(); void setMutexParams(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs); /** * 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 getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const; /** * This updates the SPI clock default polarity. Only setting the mode does not update * the line state, which can be an issue on mode switches because the clock line will * switch the state after the chip select is pulled low. * * It is recommended to call this function after #setSpiSpeedAndMode and after locking the * CS mutex if the SPI bus has multiple SPI devices with different speed and SPI modes attached. * @param spiFd */ void updateLinePolarity(int spiFd); const std::string& getSpiDev() const; void performSpiWiretapping(SpiCookie* spiCookie); ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer); private: struct SpiInstance { SpiInstance(size_t maxRecvSize) : replyBuffer(std::vector(maxRecvSize)) {} std::vector replyBuffer; }; GpioIF* gpioComIF = nullptr; std::string dev = ""; /** * Protects the chip select operations. Lock when GPIO is pulled low, unlock after it was * pulled high */ MutexIF* csMutex = nullptr; // MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; // uint32_t timeoutMs = DEFAULT_MUTEX_TIMEOUT; spi_ioc_transfer clockUpdateTransfer = {}; using SpiDeviceMap = std::unordered_map; using SpiDeviceMapIter = SpiDeviceMap::iterator; SpiDeviceMap spiDeviceMap; ReturnValue_t performHalfDuplexReception(SpiCookie* spiCookie); }; #endif /* LINUX_SPI_SPICOMIF_H_ */