fsfw/src/fsfw/osal/common/UdpTcPollingTask.cpp

169 lines
5.9 KiB
C++
Raw Normal View History

2021-07-13 21:02:53 +02:00
#include "fsfw/osal/common/UdpTcPollingTask.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/objectmanager/ObjectManager.h"
2022-02-02 10:29:30 +01:00
#include "fsfw/osal/common/tcpipHelpers.h"
#include "fsfw/platform.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
2020-09-06 15:46:49 +02:00
2021-05-12 16:47:53 +02:00
#ifdef PLATFORM_WIN
2020-09-06 15:46:49 +02:00
#include <winsock2.h>
2021-05-12 16:47:53 +02:00
#elif defined(PLATFORM_UNIX)
2021-03-21 12:51:28 +01:00
#include <sys/socket.h>
2022-02-02 10:29:30 +01:00
#include <sys/types.h>
2021-03-21 12:51:28 +01:00
#endif
2021-03-15 13:06:13 +01:00
//! Debugging preprocessor define.
2022-02-02 10:29:30 +01:00
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
2022-05-01 17:48:49 +02:00
const timeval UdpTcPollingTask::DEFAULT_TIMEOUT = {0, 500000};
2022-02-02 10:29:30 +01:00
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUdpBridge,
size_t maxRecvSize, double timeoutSeconds)
: SystemObject(objectId), tmtcBridgeId(tmtcUdpBridge) {
2022-05-01 17:48:49 +02:00
if (maxRecvSize > 0) {
this->frameSize = maxRecvSize;
2022-02-02 10:29:30 +01:00
} else {
this->frameSize = DEFAULT_MAX_RECV_SIZE;
}
/* Set up reception buffer with specified frame size.
For now, it is assumed that only one frame is held in the buffer! */
receptionBuffer.reserve(this->frameSize);
receptionBuffer.resize(this->frameSize);
if (timeoutSeconds == -1) {
2022-05-01 17:48:49 +02:00
receptionTimeout = UdpTcPollingTask::DEFAULT_TIMEOUT;
2022-02-02 10:29:30 +01:00
} else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
2020-09-06 15:46:49 +02:00
}
2022-05-01 17:48:49 +02:00
[[noreturn]] ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
2022-02-02 10:29:30 +01:00
/* Sender Address is cached here. */
2022-05-01 17:48:49 +02:00
struct sockaddr senderAddress {};
2022-02-02 10:29:30 +01:00
socklen_t senderAddressSize = sizeof(senderAddress);
/* Poll for new UDP datagrams in permanent loop. */
while (true) {
2022-05-01 17:48:49 +02:00
ssize_t bytesReceived =
2022-02-02 10:29:30 +01:00
recvfrom(this->serverSocket, reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
receptionFlags, &senderAddress, &senderAddressSize);
if (bytesReceived == SOCKET_ERROR) {
/* Handle error */
2021-01-03 14:16:52 +01:00
#if FSFW_CPP_OSTREAM_ENABLED == 1
2022-02-02 10:29:30 +01:00
sif::error << "UdpTcPollingTask::performOperation: Reception error." << std::endl;
#endif
2022-02-02 10:29:30 +01:00
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::RECVFROM_CALL, 1000);
continue;
}
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
2022-02-02 10:29:30 +01:00
sif::debug << "UdpTcPollingTask::performOperation: " << bytesReceived << " bytes received"
<< std::endl;
#else
#endif
#endif /* FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1 */
2020-09-06 15:46:49 +02:00
2022-02-02 10:29:30 +01:00
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if (result != HasReturnvaluesIF::RETURN_FAILED) {
2021-03-21 13:02:14 +01:00
}
2022-02-02 10:29:30 +01:00
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
2020-09-06 15:46:49 +02:00
}
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
2022-02-02 10:29:30 +01:00
store_address_t storeId;
2021-03-12 02:15:21 +01:00
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
2022-02-02 10:29:30 +01:00
arrayprinter::print(receptionBuffer.data(), bytesRead);
2021-03-08 23:00:53 +01:00
#endif
2021-03-12 02:15:21 +01:00
2022-02-02 10:29:30 +01:00
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
2021-03-12 02:15:21 +01:00
#if FSFW_VERBOSE_LEVEL >= 1
2021-01-03 14:16:52 +01:00
#if FSFW_CPP_OSTREAM_ENABLED == 1
2022-02-02 10:29:30 +01:00
sif::warning << "UdpTcPollingTask::transferPusToSoftwareBus: Data storage failed." << std::endl;
sif::warning << "Packet size: " << bytesRead << std::endl;
2021-03-12 02:15:21 +01:00
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
2022-02-02 10:29:30 +01:00
return HasReturnvaluesIF::RETURN_FAILED;
}
2020-09-06 15:46:49 +02:00
2022-02-02 10:29:30 +01:00
TmTcMessage message(storeId);
2020-09-06 15:46:49 +02:00
2022-02-02 10:29:30 +01:00
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
2021-03-12 02:15:21 +01:00
#if FSFW_VERBOSE_LEVEL >= 1
2021-01-03 14:16:52 +01:00
#if FSFW_CPP_OSTREAM_ENABLED == 1
2022-02-02 10:29:30 +01:00
sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: "
" Sending message to queue failed"
<< std::endl;
2021-03-12 02:15:21 +01:00
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
2022-02-02 10:29:30 +01:00
tcStore->deleteData(storeId);
}
return result;
2020-09-06 15:46:49 +02:00
}
ReturnValue_t UdpTcPollingTask::initialize() {
2022-02-02 10:29:30 +01:00
tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
2021-01-03 14:16:52 +01:00
#if FSFW_CPP_OSTREAM_ENABLED == 1
2022-02-02 10:29:30 +01:00
sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl;
#endif
2022-02-02 10:29:30 +01:00
return ObjectManagerIF::CHILD_INIT_FAILED;
}
2020-09-06 15:46:49 +02:00
2022-02-02 10:29:30 +01:00
tmtcBridge = ObjectManager::instance()->get<UdpTmTcBridge>(tmtcBridgeId);
if (tmtcBridge == nullptr) {
2021-01-03 14:16:52 +01:00
#if FSFW_CPP_OSTREAM_ENABLED == 1
2022-02-02 10:29:30 +01:00
sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" << std::endl;
#endif
2022-02-02 10:29:30 +01:00
return ObjectManagerIF::CHILD_INIT_FAILED;
}
2022-02-02 10:29:30 +01:00
ReturnValue_t result = TcpIpBase::initialize();
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
2022-02-02 10:29:30 +01:00
return HasReturnvaluesIF::RETURN_OK;
2020-09-06 15:46:49 +02:00
}
ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() {
2022-02-02 10:29:30 +01:00
/* Initialize the destination after task creation. This ensures
that the destination has already been set in the TMTC bridge. */
targetTcDestination = tmtcBridge->getRequestQueue();
/* The server socket is set up in the bridge intialization. Calling this function here
ensures that it is set up regardless of which class was initialized first */
this->serverSocket = tmtcBridge->serverSocket;
return HasReturnvaluesIF::RETURN_OK;
2020-09-06 15:46:49 +02:00
}
void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
2021-05-12 16:47:53 +02:00
#ifdef PLATFORM_WIN
2022-02-02 10:29:30 +01:00
DWORD timeoutMs = timeoutSeconds * 1000.0;
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
if (result == -1) {
2021-01-03 14:16:52 +01:00
#if FSFW_CPP_OSTREAM_ENABLED == 1
2022-02-02 10:29:30 +01:00
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with "
<< strerror(errno) << std::endl;
#endif
2022-02-02 10:29:30 +01:00
}
2021-05-12 16:47:53 +02:00
#elif defined(PLATFORM_UNIX)
2022-05-14 11:32:51 +02:00
timeval tval{};
2022-02-02 10:29:30 +01:00
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(receptionTimeout));
if (result == -1) {
2021-03-21 13:02:14 +01:00
#if FSFW_CPP_OSTREAM_ENABLED == 1
2022-02-02 10:29:30 +01:00
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with "
<< strerror(errno) << std::endl;
2021-03-21 13:02:14 +01:00
#endif
2022-02-02 10:29:30 +01:00
}
#endif
2020-09-06 15:46:49 +02:00
}