#include #include #include #include "fsfw/serviceinterface/ServiceInterface.h" #include PapbVcInterface::PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId, gpioId_t papbEmptyId, std::string uioFile, int mapNum) : gpioComIF(gpioComIF), papbBusyId(papbBusyId), papbEmptyId(papbEmptyId), uioFile(std::move(uioFile)), mapNum(mapNum) {} PapbVcInterface::~PapbVcInterface() {} ReturnValue_t PapbVcInterface::initialize() { UioMapper uioMapper(uioFile, mapNum); uint32_t* baseReg; ReturnValue_t result = uioMapper.getMappedAdress(&baseReg, UioMapper::Permissions::WRITE_ONLY); if (result != returnvalue::OK) { return result; } vcBaseReg = baseReg; return returnvalue::OK; } ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) { if (pollPapbBusySignal(0) == returnvalue::OK) { startPacketTransfer(); } else { return DirectTmSinkIF::IS_BUSY; } for (size_t idx = 0; idx < size; idx++) { if (pollPapbBusySignal(20) == returnvalue::OK) { *(vcBaseReg + DATA_REG_OFFSET) = static_cast(data[idx]); } else { abortPacketTransfer(); return returnvalue::FAILED; } } if (pollPapbBusySignal(20) == returnvalue::OK) { completePacketTransfer(); } else { abortPacketTransfer(); return returnvalue::FAILED; } return returnvalue::OK; } void PapbVcInterface::startPacketTransfer() { *vcBaseReg = CONFIG_START; } void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; } ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries) const { gpio::Levels papbBusyState = gpio::Levels::LOW; ReturnValue_t result; uint32_t busyIdx = 0; nextDelay.tv_nsec = 1000; while (true) { /** Check if PAPB interface is ready to receive data */ result = gpioComIF->readGpio(papbBusyId, papbBusyState); if (result != returnvalue::OK) { sif::warning << "PapbVcInterface::pollPapbBusySignal: Failed to read papb busy signal" << std::endl; return returnvalue::FAILED; } if (papbBusyState == gpio::Levels::HIGH) { return returnvalue::OK; } busyIdx++; if (busyIdx >= maxPollRetries) { return PAPB_BUSY; } // Ignore signal handling here for now. nanosleep(&nextDelay, &remDelay); // Adaptive delay. if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) { nextDelay.tv_nsec *= 2; } } return returnvalue::OK; } void PapbVcInterface::isVcInterfaceBufferEmpty() { ReturnValue_t result = returnvalue::OK; gpio::Levels papbEmptyState = gpio::Levels::HIGH; result = gpioComIF->readGpio(papbEmptyId, papbEmptyState); if (result != returnvalue::OK) { sif::warning << "PapbVcInterface::isVcInterfaceBufferEmpty: Failed to read papb empty signal" << std::endl; return; } if (papbEmptyState == gpio::Levels::HIGH) { sif::debug << "PapbVcInterface::isVcInterfaceBufferEmpty: Buffer is empty" << std::endl; } else { sif::debug << "PapbVcInterface::isVcInterfaceBufferEmpty: Buffer is not empty" << std::endl; } return; } bool PapbVcInterface::isBusy() const { return pollPapbBusySignal(0) == PAPB_BUSY; } void PapbVcInterface::cancelTransfer() { abortPacketTransfer(); } ReturnValue_t PapbVcInterface::sendTestFrame() { /** Size of one complete transfer frame data field amounts to 1105 bytes */ uint8_t testPacket[1105]; /** Fill one test packet */ for (int idx = 0; idx < 1105; idx++) { testPacket[idx] = static_cast(idx & 0xFF); } ReturnValue_t result = write(testPacket, 1105); if (result != returnvalue::OK) { return result; } return returnvalue::OK; } void PapbVcInterface::abortPacketTransfer() { *vcBaseReg = CONFIG_ABORT; }