1
0
forked from fsfw/fsfw

Merge remote-tracking branch 'origin/development' into gaisser_make_linux_realtime_optional

This commit is contained in:
2021-04-20 13:06:11 +02:00
109 changed files with 2487 additions and 1628 deletions

View File

@ -1,34 +1,35 @@
# Check the OS_FSFW variable
if(${OS_FSFW} STREQUAL "freertos")
add_subdirectory(FreeRTOS)
add_subdirectory(FreeRTOS)
elseif(${OS_FSFW} STREQUAL "rtems")
add_subdirectory(rtems)
add_subdirectory(rtems)
elseif(${OS_FSFW} STREQUAL "linux")
add_subdirectory(linux)
add_subdirectory(linux)
elseif(${OS_FSFW} STREQUAL "host")
add_subdirectory(host)
if (WIN32)
add_subdirectory(windows)
elseif(UNIX)
target_sources(${LIB_FSFW_NAME}
PUBLIC
linux/TcUnixUdpPollingTask.cpp
linux/TmTcUnixUdpBridge.cpp
)
endif ()
add_subdirectory(host)
if (WIN32)
add_subdirectory(windows)
elseif(UNIX)
# We still need to pull in some Linux specific sources
target_sources(${LIB_FSFW_NAME} PUBLIC
linux/tcpipHelpers.cpp
)
endif ()
else()
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
# Not set. Assumuing this is a host build, try to determine host OS
if (WIN32)
add_subdirectory(host)
add_subdirectory(windows)
elseif (UNIX)
add_subdirectory(linux)
else ()
# MacOS or other OSes have not been tested yet / are not supported.
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
endif()
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
# Not set. Assumuing this is a host build, try to determine host OS
if (WIN32)
add_subdirectory(host)
add_subdirectory(windows)
elseif (UNIX)
add_subdirectory(linux)
else ()
# MacOS or other OSes have not been tested yet / are not supported.
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
endif()
endif()
endif()
add_subdirectory(common)

View File

@ -111,7 +111,7 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
struct tm time_tm;
struct tm time_tm = {};
time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1;

View File

@ -135,7 +135,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
QueueHandle_t destination = nullptr;
if(sendTo == MessageQueueIF::NO_QUEUE or sendTo == 0x00) {
return MessageQueueIF::DESTINVATION_INVALID;
return MessageQueueIF::DESTINATION_INVALID;
}
else {
destination = reinterpret_cast<QueueHandle_t>(sendTo);

View File

@ -0,0 +1,16 @@
if(DEFINED WIN32 OR DEFINED UNIX)
target_sources(${LIB_FSFW_NAME} PRIVATE
tcpipCommon.cpp
TcpIpBase.cpp
UdpTcPollingTask.cpp
UdpTmTcBridge.cpp
TcpTmTcServer.cpp
)
endif()
if(WIN32)
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
wsock32
ws2_32
)
endif()

54
osal/common/TcpIpBase.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "TcpIpBase.h"
#ifdef __unix__
#include <errno.h>
#include <unistd.h>
#endif
TcpIpBase::TcpIpBase() {
}
ReturnValue_t TcpIpBase::initialize() {
#ifdef _WIN32
/* Initiates Winsock DLL. */
WSAData wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable Winsock DLL. */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: " <<
err << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
#endif
return HasReturnvaluesIF::RETURN_OK;
}
TcpIpBase::~TcpIpBase() {
closeSocket(serverSocket);
#ifdef _WIN32
WSACleanup();
#endif
}
int TcpIpBase::closeSocket(socket_t socket) {
#ifdef _WIN32
return closesocket(socket);
#elif defined(__unix__)
return close(socket);
#endif
}
int TcpIpBase::getLastSocketError() {
#ifdef _WIN32
return WSAGetLastError();
#elif defined(__unix__)
return errno;
#endif
}

50
osal/common/TcpIpBase.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef FSFW_OSAL_COMMON_TCPIPIF_H_
#define FSFW_OSAL_COMMON_TCPIPIF_H_
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#ifdef _WIN32
#include <winsock2.h>
#elif defined(__unix__)
#include <sys/socket.h>
#endif
class TcpIpBase {
protected:
#ifdef _WIN32
static constexpr int SHUT_RECV = SD_RECEIVE;
static constexpr int SHUT_SEND = SD_SEND;
static constexpr int SHUT_BOTH = SD_BOTH;
using socket_t = SOCKET;
#elif defined(__unix__)
using socket_t = int;
static constexpr int INVALID_SOCKET = -1;
static constexpr int SOCKET_ERROR = -1;
static constexpr int SHUT_RECV = SHUT_RD;
static constexpr int SHUT_SEND = SHUT_WR;
static constexpr int SHUT_BOTH = SHUT_RDWR;
#endif
TcpIpBase();
virtual ~TcpIpBase();
ReturnValue_t initialize();
int closeSocket(socket_t socket);
int getLastSocketError();
socket_t serverSocket = 0;
};
#endif /* FSFW_OSAL_COMMON_TCPIPIF_H_ */

View File

@ -0,0 +1,132 @@
#include "TcpTmTcServer.h"
#include "tcpipHelpers.h"
#include "../../serviceinterface/ServiceInterface.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <netdb.h>
#endif
const std::string TcpTmTcServer::DEFAULT_TCP_SERVER_PORT = "7301";
const std::string TcpTmTcServer::DEFAULT_TCP_CLIENT_PORT = "7302";
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
std::string customTcpServerPort):
SystemObject(objectId), tcpPort(customTcpServerPort) {
if(tcpPort == "") {
tcpPort = DEFAULT_TCP_SERVER_PORT;
}
}
ReturnValue_t TcpTmTcServer::initialize() {
using namespace tcpip;
ReturnValue_t result = TcpIpBase::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
int retval = 0;
struct addrinfo *addrResult = nullptr;
struct addrinfo hints = {};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult);
if (retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcpTmTcServer: Retrieving address info failed!" <<
std::endl;
#endif
handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL);
return HasReturnvaluesIF::RETURN_FAILED;
}
/* Open TCP (stream) socket */
listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype,
addrResult->ai_protocol);
if(listenerTcpSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcWinTcpServer: Socket creation failed!" << std::endl;
#endif
freeaddrinfo(addrResult);
handleError(Protocol::TCP, ErrorSources::SOCKET_CALL);
return HasReturnvaluesIF::RETURN_FAILED;
}
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if(retval == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TcWinTcpServer::TcpTmTcServer: Binding socket failed!" <<
std::endl;
#endif
freeaddrinfo(addrResult);
handleError(Protocol::TCP, ErrorSources::BIND_CALL);
return HasReturnvaluesIF::RETURN_FAILED;
}
freeaddrinfo(addrResult);
return HasReturnvaluesIF::RETURN_OK;
}
TcpTmTcServer::~TcpTmTcServer() {
closeSocket(listenerTcpSocket);
}
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
using namespace tcpip;
/* If a connection is accepted, the corresponding socket will be assigned to the new socket */
socket_t clientSocket = 0;
sockaddr clientSockAddr = {};
socklen_t connectorSockAddrLen = 0;
int retval = 0;
/* Listen for connection requests permanently for lifetime of program */
while(true) {
retval = listen(listenerTcpSocket, currentBacklog);
if(retval == SOCKET_ERROR) {
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
continue;
}
clientSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
if(clientSocket == INVALID_SOCKET) {
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
closeSocket(clientSocket);
continue;
};
retval = recv(clientSocket, reinterpret_cast<char*>(receptionBuffer.data()),
receptionBuffer.size(), 0);
if(retval > 0) {
#if FSFW_TCP_RCV_WIRETAPPING_ENABLED == 1
sif::info << "TcpTmTcServer::performOperation: Received " << retval << " bytes."
std::endl;
#endif
handleError(Protocol::TCP, ErrorSources::RECV_CALL, 500);
}
else if(retval == 0) {
}
else {
}
/* Done, shut down connection */
retval = shutdown(clientSocket, SHUT_SEND);
closeSocket(clientSocket);
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,53 @@
#ifndef FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_
#define FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_
#include "TcpIpBase.h"
#include "../../objectmanager/SystemObject.h"
#include "../../tasks/ExecutableObjectIF.h"
#ifdef __unix__
#include <sys/socket.h>
#endif
#include <string>
#include <vector>
//! Debugging preprocessor define.
#define FSFW_TCP_RCV_WIRETAPPING_ENABLED 0
/**
* @brief Windows TCP server used to receive telecommands on a Windows Host
* @details
* Based on: https://docs.microsoft.com/en-us/windows/win32/winsock/complete-server-code
*/
class TcpTmTcServer:
public SystemObject,
public TcpIpBase,
public ExecutableObjectIF {
public:
/* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_TCP_SERVER_PORT;
static const std::string DEFAULT_TCP_CLIENT_PORT;
TcpTmTcServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
std::string customTcpServerPort = "");
virtual~ TcpTmTcServer();
ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t opCode) override;
private:
std::string tcpPort;
socket_t listenerTcpSocket = 0;
struct sockaddr tcpAddress;
int tcpAddrLen = sizeof(tcpAddress);
int currentBacklog = 3;
std::vector<uint8_t> receptionBuffer;
int tcpSockOpt = 0;
};
#endif /* FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ */

View File

@ -0,0 +1,177 @@
#include "UdpTcPollingTask.h"
#include "tcpipHelpers.h"
#include "../../globalfunctions/arrayprinter.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#endif
//! Debugging preprocessor define.
#define FSFW_UDP_RCV_WIRETAPPING_ENABLED 0
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t maxRecvSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
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) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
UdpTcPollingTask::~UdpTcPollingTask() {}
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
/* Sender Address is cached here. */
struct sockaddr senderAddress;
socklen_t senderAddressSize = sizeof(senderAddress);
/* Poll for new UDP datagrams in permanent loop. */
while(true) {
int bytesReceived = recvfrom(
this->serverSocket,
reinterpret_cast<char*>(receptionBuffer.data()),
frameSize,
receptionFlags,
&senderAddress,
&senderAddressSize
);
if(bytesReceived == SOCKET_ERROR) {
/* Handle error */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UdpTcPollingTask::performOperation: Reception error." << std::endl;
#endif
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::RECVFROM_CALL, 1000);
continue;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1
sif::debug << "UdpTcPollingTask::performOperation: " << bytesReceived <<
" bytes received" << std::endl;
#endif
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
#if FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1
arrayprinter::print(receptionBuffer.data(), bytesRead);
#endif
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning<< "UdpTcPollingTask::transferPusToSoftwareBus: Data storage failed." <<
std::endl;
sif::warning << "Packet size: " << bytesRead << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: "
" Sending message to queue failed" << std::endl;
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
tcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t UdpTcPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<UdpTmTcBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" <<
std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
ReturnValue_t result = TcpIpBase::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() {
/* 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;
}
void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
#ifdef _WIN32
DWORD timeoutMs = timeoutSeconds * 1000.0;
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
#endif
}
#elif defined(__unix__)
timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
&tval, sizeof(receptionTimeout));
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
#endif
}
#endif
}

View File

@ -1,7 +1,7 @@
#ifndef FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
#define FSFW_OSAL_WINDOWS_TCSOCKETPOLLINGTASK_H_
#include "TmTcWinUdpBridge.h"
#include "UdpTmTcBridge.h"
#include "../../objectmanager/SystemObject.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "../../storagemanager/StorageManagerIF.h"
@ -9,25 +9,22 @@
#include <vector>
/**
* @brief This class can be used to implement the polling of a Unix socket,
* using UDP for now.
* @details
* The task will be blocked while the specified number of bytes has not been
* received, so TC reception is handled inside a separate task.
* This class caches the IP address of the sender. It is assumed there
* is only one sender for now.
* @brief This class should be used with the UdpTmTcBridge to implement a UDP server
* for receiving and sending PUS TMTC.
*/
class TcWinUdpPollingTask: public SystemObject,
class UdpTcPollingTask:
public TcpIpBase,
public SystemObject,
public ExecutableObjectIF {
friend class TmTcWinUdpBridge;
public:
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
static constexpr size_t DEFAULT_MAX_RECV_SIZE = 1500;
//! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
static constexpr timeval DEFAULT_TIMEOUT = {0, 500};
TcWinUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
size_t frameSize = 0, double timeoutSeconds = -1);
virtual~ TcWinUdpPollingTask();
UdpTcPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
size_t maxRecvSize = 0, double timeoutSeconds = -1);
virtual~ UdpTcPollingTask();
/**
* Turn on optional timeout for UDP polling. In the default mode,
@ -46,14 +43,11 @@ protected:
private:
//! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT;
TmTcWinUdpBridge* tmtcBridge = nullptr;
UdpTmTcBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! Reception flags: https://linux.die.net/man/2/recvfrom.
int receptionFlags = 0;
//! Server socket, which is member of TMTC bridge and is assigned in
//! constructor
SOCKET serverUdpSocket = 0;
//! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
int receptionFlags = 0;
std::vector<uint8_t> receptionBuffer;
@ -61,7 +55,6 @@ private:
timeval receptionTimeout;
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
void handleReadError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */

View File

@ -0,0 +1,172 @@
#include "tcpipHelpers.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/ipc/MutexGuard.h>
#include <fsfw/osal/common/UdpTmTcBridge.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <netdb.h>
#include <arpa/inet.h>
#endif
//! Debugging preprocessor define.
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
const std::string UdpTmTcBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
if(udpServerPort == "") {
this->udpServerPort = DEFAULT_UDP_SERVER_PORT;
}
else {
this->udpServerPort = udpServerPort;
}
mutex = MutexFactory::instance()->createMutex();
communicationLinkUp = false;
}
ReturnValue_t UdpTmTcBridge::initialize() {
ReturnValue_t result = TmTcBridge::initialize();
if(result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::initialize: TmTcBridge initialization failed!"
<< std::endl;
#endif
return result;
}
#ifdef _WIN32
/* Initiates Winsock DLL. */
WSAData wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: " <<
err << std::endl;
#else
sif::printError("TmTcUdpBridge::TmTcUdpBridge: WSAStartup failed with error: %d\n",
err);
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
#endif
struct addrinfo *addrResult = nullptr;
struct addrinfo hints = {};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
/* Set up UDP socket:
https://en.wikipedia.org/wiki/Getaddrinfo
Passing nullptr as the first parameter and specifying AI_PASSIVE in hints will cause
getaddrinfo to assign the address 0.0.0.0 (any address) */
int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult);
if (retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Retrieving address info failed!" <<
std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol);
if(serverSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::TmTcUdpBridge: Could not open UDP socket!" <<
std::endl;
#endif
freeaddrinfo(addrResult);
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL);
return HasReturnvaluesIF::RETURN_FAILED;
}
retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if(retval != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUdpBridge::TmTcUdpBridge: Could not bind "
"local port (" << udpServerPort << ") to server socket!" << std::endl;
#endif
freeaddrinfo(addrResult);
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL);
}
freeaddrinfo(addrResult);
return HasReturnvaluesIF::RETURN_OK;
}
UdpTmTcBridge::~UdpTmTcBridge() {
if(mutex != nullptr) {
MutexFactory::instance()->deleteMutex(mutex);
}
}
ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
/* The target address can be set by different threads so this lock ensures thread-safety */
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
char ipAddress [15];
sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
&clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
#endif
int bytesSent = sendto(
serverSocket,
reinterpret_cast<const char*>(data),
dataLen,
flags,
&clientAddress,
clientAddressLen
);
if(bytesSent == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcUdpBridge::sendTm: Send operation failed." << std::endl;
#endif
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
}
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent << " bytes were"
" sent." << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
}
void UdpTmTcBridge::checkAndSetClientAddress(sockaddr& newAddress) {
/* The target address can be set by different threads so this lock ensures thread-safety */
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
char ipAddress [15];
sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
&newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
&clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
#endif
registerCommConnect();
/* Set new IP address to reply to */
clientAddress = newAddress;
clientAddressLen = sizeof(clientAddress);
}
void UdpTmTcBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
dur_millis_t timeoutMs) {
this->timeoutType = timeoutType;
this->mutexTimeoutMs = timeoutMs;
}

View File

@ -0,0 +1,60 @@
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
#include "TcpIpBase.h"
#include "../../tmtcservices/TmTcBridge.h"
#ifdef _WIN32
#include <ws2tcpip.h>
#elif defined(__unix__)
#include <sys/socket.h>
#endif
#include <string>
/**
* @brief This class should be used with the UdpTcPollingTask to implement a UDP server
* for receiving and sending PUS TMTC.
*/
class UdpTmTcBridge:
public TmTcBridge,
public TcpIpBase {
friend class UdpTcPollingTask;
public:
/* The ports chosen here should not be used by any other process. */
static const std::string DEFAULT_UDP_SERVER_PORT;
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort = "");
virtual~ UdpTmTcBridge();
/**
* Set properties of internal mutex.
*/
void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs);
ReturnValue_t initialize() override;
void checkAndSetClientAddress(sockaddr& clientAddress);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
std::string udpServerPort;
struct sockaddr clientAddress;
socklen_t clientAddressLen = 0;
//! Access to the client address is mutex protected as it is set by another task.
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
dur_millis_t mutexTimeoutMs = 20;
MutexIF* mutex;
};
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */

View File

@ -0,0 +1,36 @@
#include "tcpipCommon.h"
void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string &protStr,
std::string &srcString) {
if(protocol == Protocol::TCP) {
protStr = "TCP";
}
else if(protocol == Protocol::UDP) {
protStr = "UDP";
}
else {
protStr = "Unknown protocol";
}
if(errorSrc == ErrorSources::SETSOCKOPT_CALL) {
srcString = "setsockopt call";
}
else if(errorSrc == ErrorSources::SOCKET_CALL) {
srcString = "socket call";
}
else if(errorSrc == ErrorSources::LISTEN_CALL) {
srcString = "listen call";
}
else if(errorSrc == ErrorSources::ACCEPT_CALL) {
srcString = "accept call";
}
else if(errorSrc == ErrorSources::RECVFROM_CALL) {
srcString = "recvfrom call";
}
else if(errorSrc == ErrorSources::GETADDRINFO_CALL) {
srcString = "getaddrinfo call";
}
else {
srcString = "unknown call";
}
}

35
osal/common/tcpipCommon.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef FSFW_OSAL_COMMON_TCPIPCOMMON_H_
#define FSFW_OSAL_COMMON_TCPIPCOMMON_H_
#include "../../timemanager/clockDefinitions.h"
#include <string>
namespace tcpip {
const char* const DEFAULT_SERVER_PORT = "7301";
enum class Protocol {
UDP,
TCP
};
enum class ErrorSources {
GETADDRINFO_CALL,
SOCKET_CALL,
SETSOCKOPT_CALL,
BIND_CALL,
RECV_CALL,
RECVFROM_CALL,
LISTEN_CALL,
ACCEPT_CALL,
SENDTO_CALL
};
void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr,
std::string& srcString);
}
#endif /* FSFW_OSAL_COMMON_TCPIPCOMMON_H_ */

View File

@ -0,0 +1,15 @@
#ifndef FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
#define FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
#include "../../timemanager/clockDefinitions.h"
#include "tcpipCommon.h"
namespace tcpip {
void handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration = 0);
}
#endif /* FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_ */

View File

@ -10,6 +10,7 @@ target_sources(${LIB_FSFW_NAME}
QueueMapManager.cpp
SemaphoreFactory.cpp
TaskFactory.cpp
taskHelpers.cpp
)
if(UNIX)

View File

@ -1,10 +1,9 @@
#include "taskHelpers.h"
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
@ -12,6 +11,7 @@
#if defined(WIN32)
#include <windows.h>
#include "../windows/winTaskHelpers.h"
#elif defined(LINUX)
#include <pthread.h>
#endif
@ -24,34 +24,12 @@ FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
#elif defined(LINUX)
// TODO: we can just copy and paste the code from the linux OSAL here.
#if defined(_WIN32)
tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
#elif defined(__unix__)
// TODO: We could reuse existing code here.
#endif
tasks::insertTaskName(mainThread.get_id(), taskName);
}
FixedTimeslotTask::~FixedTimeslotTask(void) {
@ -60,7 +38,6 @@ FixedTimeslotTask::~FixedTimeslotTask(void) {
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void FixedTimeslotTask::taskEntryPoint(void* argument) {
@ -141,8 +118,11 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
sif::error << "Component " << std::hex << "0x" << componentId << "not found, "
"not adding it to PST.." << std::dec << std::endl;
#else
sif::printError("Component 0x%08x not found, not adding it to PST..\n",
static_cast<unsigned int>(componentId));
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}

View File

@ -3,7 +3,7 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
#include "../../ipc/MutexGuard.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) {
@ -63,9 +63,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(messageQueue.empty()) {
return MessageQueueIF::EMPTY;
}
// not sure this will work..
//*message = std::move(messageQueue.front());
MutexHelper mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20);
MutexGuard mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20);
MessageQueueMessage* currentMessage = &messageQueue.front();
std::copy(currentMessage->getBuffer(),
currentMessage->getBuffer() + messageSize, message->getBuffer());
@ -130,7 +128,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
return HasReturnvaluesIF::RETURN_FAILED;
}
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexHelper mutexLock(targetQueue->queueLock,
MutexGuard mutexLock(targetQueue->queueLock,
MutexIF::TimeoutType::WAITING, 20);
// not ideal, works for now though.
MessageQueueMessage* mqmMessage =

View File

@ -24,5 +24,7 @@ MutexIF* MutexFactory::createMutex() {
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
if(mutex != nullptr) {
delete mutex;
}
}

View File

@ -1,5 +1,6 @@
#include "Mutex.h"
#include "PeriodicTask.h"
#include "taskHelpers.h"
#include "../../ipc/MutexFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
@ -10,7 +11,8 @@
#if defined(WIN32)
#include <processthreadsapi.h>
#elif defined(LINUX)
#include <fsfw/osal/windows/winTaskHelpers.h>
#elif defined(__unix__)
#include <pthread.h>
#endif
@ -22,34 +24,12 @@ PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
// It is probably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
#endif
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#if defined(_WIN32)
tasks::setTaskPriority(reinterpret_cast<HANDLE>(mainThread.native_handle()), setPriority);
#elif defined(__unix__)
// TODO: We could reuse existing code here.
#endif
tasks::insertTaskName(mainThread.get_id(), taskName);
}
PeriodicTask::~PeriodicTask(void) {
@ -58,7 +38,6 @@ PeriodicTask::~PeriodicTask(void) {
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void PeriodicTask::taskEntryPoint(void* argument) {

View File

@ -2,7 +2,7 @@
#include "../../serviceinterface/ServiceInterface.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
#include "../../ipc/MutexGuard.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
@ -10,6 +10,10 @@ QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex();
}
QueueMapManager::~QueueMapManager() {
MutexFactory::instance()->deleteMutex(mapLock);
}
QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager();
@ -43,7 +47,7 @@ ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const {
MutexHelper(mapLock, MutexIF::TimeoutType::WAITING, 50);
MutexGuard(mapLock, MutexIF::TimeoutType::WAITING, 50);
auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) {
return queueIter->second;

View File

@ -36,6 +36,8 @@ public:
private:
//! External instantiation is forbidden.
QueueMapManager();
~QueueMapManager();
uint32_t queueCounter = 0;
MutexIF* mapLock;
QueueMap queueMap;

View File

@ -1,7 +1,5 @@
#include "../../tasks/SemaphoreFactory.h"
#include "../../osal/linux/BinarySemaphore.h"
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../serviceinterface/ServiceInterface.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;

View File

@ -1,14 +1,16 @@
#include "taskHelpers.h"
#include "../../tasks/TaskFactory.h"
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../osal/host/PeriodicTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <chrono>
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Will propably not be used for hosted implementation
// Not used for the host implementation for now because C++ thread abstraction is used
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() {
@ -49,8 +51,12 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
}
void TaskFactory::printMissedDeadline() {
/* TODO: Implement */
return;
std::string name = tasks::getTaskName(std::this_thread::get_id());
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TaskFactory::printMissedDeadline: " << name << std::endl;
#else
sif::printWarning("TaskFactory::printMissedDeadline: %s\n", name);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}

27
osal/host/taskHelpers.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "taskHelpers.h"
#include <map>
#include <mutex>
std::mutex nameMapLock;
std::map<std::thread::id, std::string> taskNameMap;
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) {
std::lock_guard<std::mutex> lg(nameMapLock);
auto returnPair = taskNameMap.emplace(threadId, taskName);
if(not returnPair.second) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
std::string tasks::getTaskName(std::thread::id threadId) {
std::lock_guard<std::mutex> lg(nameMapLock);
auto resultIter = taskNameMap.find(threadId);
if(resultIter != taskNameMap.end()) {
return resultIter->second;
}
else {
return "Unknown task";
}
}

16
osal/host/taskHelpers.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef FSFW_OSAL_HOST_TASKHELPERS_H_
#define FSFW_OSAL_HOST_TASKHELPERS_H_
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
#include <thread>
namespace tasks {
ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName);
std::string getTaskName(std::thread::id threadId);
}
#endif /* FSFW_OSAL_HOST_TASKHELPERS_H_ */

View File

@ -13,9 +13,8 @@ target_sources(${LIB_FSFW_NAME}
QueueFactory.cpp
SemaphoreFactory.cpp
TaskFactory.cpp
TcUnixUdpPollingTask.cpp
TmTcUnixUdpBridge.cpp
Timer.cpp
tcpipHelpers.cpp
)
find_package(Threads REQUIRED)

View File

@ -190,13 +190,15 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}else if(status==0){
}
else if (status==0) {
//Success but no message received
return MessageQueueIF::EMPTY;
} else {
}
else {
//No message was received. Keep lastPartner anyway, I might send
//something later. But still, delete packet content.
memset(message->getData(), 0, message->getMaximumMessageSize());
memset(message->getData(), 0, message->getMaximumDataSize());
switch(errno){
case EAGAIN:
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages
@ -371,7 +373,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
<<"mq_send to: " << sendTo << " sent from "
<< sentFrom << std::endl;
#endif
return DESTINVATION_INVALID;
return DESTINATION_INVALID;
}
case EINTR:
//The call was interrupted by a signal.

View File

@ -6,7 +6,7 @@
#include <errno.h>
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):
thread(0),priority(priority_),stackSize(stackSize_) {
thread(0), priority(priority_), stackSize(stackSize_) {
name[0] = '\0';
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
}
@ -75,18 +75,18 @@ bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms,
if (currentTime_ms < *prevoiusWakeTime_ms) {
/* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
&& (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true;
}
} else {
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
|| (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true;

View File

@ -2,6 +2,7 @@
#include "PeriodicPosixTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?

View File

@ -1,158 +0,0 @@
#include "TcUnixUdpPollingTask.h"
#include "../../globalfunctions/arrayprinter.h"
#include <errno.h>
TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t frameSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
else {
this->frameSize = DEFAULT_MAX_FRAME_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) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {}
ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
// Poll for new UDP datagrams in permanent loop.
while(1) {
//! Sender Address is cached here.
struct sockaddr_in senderAddress;
socklen_t senderSockLen = sizeof(senderAddress);
ssize_t bytesReceived = recvfrom(serverUdpSocket,
receptionBuffer.data(), frameSize, receptionFlags,
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);
if(bytesReceived < 0) {
// handle error
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::performOperation: Reception"
"error." << std::endl;
#endif
handleReadError();
continue;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived
// << " bytes received" << std::endl;
#endif
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->registerCommConnect();
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId,
receptionBuffer.data(), bytesRead);
// arrayprinter::print(receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
"storage failed" << std::endl;
sif::error << "Packet size: " << bytesRead << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Serial Polling: Sending message to queue failed"
<< std::endl;
#endif
tcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t TcUnixUdpPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
<< std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<TmTcUnixUdpBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
" TMTC bridge object!" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
serverUdpSocket = tmtcBridge->serverSocket;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() {
// Initialize the destination after task creation. This ensures
// that the destination will be set in the TMTC bridge.
targetTcDestination = tmtcBridge->getRequestQueue();
return HasReturnvaluesIF::RETURN_OK;
}
void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) {
timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
&tval, sizeof(receptionTimeout));
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
#endif
}
}
// TODO: sleep after error detection to prevent spam
void TcUnixUdpPollingTask::handleReadError() {
switch(errno) {
case(EAGAIN): {
// todo: When working in timeout mode, this will occur more often
// and is not an error.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout."
<< std::endl;
#endif
break;
}
default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcUnixUdpPollingTask::handleReadError: "
<< strerror(errno) << std::endl;
#endif
}
}
}

View File

@ -1,67 +0,0 @@
#ifndef FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
#define FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
#include "../../objectmanager/SystemObject.h"
#include "../../osal/linux/TmTcUnixUdpBridge.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <sys/socket.h>
#include <vector>
/**
* @brief This class can be used to implement the polling of a Unix socket,
* using UDP for now.
* @details
* The task will be blocked while the specified number of bytes has not been
* received, so TC reception is handled inside a separate task.
* This class caches the IP address of the sender. It is assumed there
* is only one sender for now.
*/
class TcUnixUdpPollingTask: public SystemObject,
public ExecutableObjectIF {
friend class TmTcUnixUdpBridge;
public:
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
//! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
size_t frameSize = 0, double timeoutSeconds = -1);
virtual~ TcUnixUdpPollingTask();
/**
* Turn on optional timeout for UDP polling. In the default mode,
* the receive function will block until a packet is received.
* @param timeoutSeconds
*/
void setTimeout(double timeoutSeconds);
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected:
StorageManagerIF* tcStore = nullptr;
private:
//! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT;
TmTcUnixUdpBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! Reception flags: https://linux.die.net/man/2/recvfrom.
int receptionFlags = 0;
//! Server socket, which is member of TMTC bridge and is assigned in
//! constructor
int serverUdpSocket = 0;
std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0;
timeval receptionTimeout;
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
void handleReadError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */

View File

@ -1,206 +0,0 @@
#include "TmTcUnixUdpBridge.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../ipc/MutexHelper.h"
#include <errno.h>
#include <arpa/inet.h>
TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId,
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort, uint16_t clientPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
if(serverPort != 0xFFFF) {
setServerPort = serverPort;
}
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
if(clientPort != 0xFFFF) {
setClientPort = clientPort;
}
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(serverSocket < 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open"
" UDP socket!" << std::endl;
#endif
handleSocketError();
return;
}
serverAddress.sin_family = AF_INET;
// Accept packets from any interface.
//serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0");
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(setServerPort);
serverAddressLen = sizeof(serverAddress);
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions,
sizeof(serverSocketOptions));
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(setClientPort);
clientAddressLen = sizeof(clientAddress);
int result = bind(serverSocket,
reinterpret_cast<struct sockaddr*>(&serverAddress),
serverAddressLen);
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind "
"local port " << setServerPort << " to server socket!"
<< std::endl;
#endif
handleBindError();
return;
}
}
TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
}
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
if(ipAddrAnySet){
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
//clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1");
clientAddressLen = sizeof(serverAddress);
}
// char ipAddress [15];
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
#endif
ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags,
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
if(bytesSent < 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed."
<< std::endl;
#endif
handleSendError();
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
// " sent." << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
}
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15];
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
#endif
// Set new IP address if it has changed.
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
clientAddressLen = sizeof(clientAddress);
}
}
void TmTcUnixUdpBridge::handleSocketError() {
// See: https://man7.org/linux/man-pages/man2/socket.2.html
switch(errno) {
case(EACCES):
case(EINVAL):
case(EMFILE):
case(ENFILE):
case(EAFNOSUPPORT):
case(ENOBUFS):
case(ENOMEM):
case(EPROTONOSUPPORT):
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
#endif
break;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleSocketError: Unknown error"
<< std::endl;
#endif
break;
}
}
void TmTcUnixUdpBridge::handleBindError() {
// See: https://man7.org/linux/man-pages/man2/bind.2.html
switch(errno) {
case(EACCES): {
/*
Ephermeral ports can be shown with following command:
sysctl -A | grep ip_local_port_range
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleBindError: Port access issue."
"Ports 1-1024 are reserved on UNIX systems and require root "
"rights while ephermeral ports should not be used as well."
<< std::endl;
#endif
}
break;
case(EADDRINUSE):
case(EBADF):
case(EINVAL):
case(ENOTSOCK):
case(EADDRNOTAVAIL):
case(EFAULT):
case(ELOOP):
case(ENAMETOOLONG):
case(ENOENT):
case(ENOMEM):
case(ENOTDIR):
case(EROFS): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
#endif
break;
}
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleBindError: Unknown error"
<< std::endl;
#endif
break;
}
}
void TmTcUnixUdpBridge::handleSendError() {
switch(errno) {
default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcUnixBridge::handleSendError: "
<< strerror(errno) << std::endl;
#else
sif::printError("TmTcUnixBridge::handleSendError: %s\n",
strerror(errno));
#endif
}
}
}
void TmTcUnixUdpBridge::setClientAddressToAny(bool ipAddrAnySet){
this->ipAddrAnySet = ipAddrAnySet;
}

View File

@ -1,51 +0,0 @@
#ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#include "../../tmtcservices/AcceptsTelecommandsIF.h"
#include "../../tmtcservices/TmTcBridge.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
class TmTcUnixUdpBridge: public TmTcBridge {
friend class TcUnixUdpPollingTask;
public:
// The ports chosen here should not be used by any other process.
// List of used ports on Linux: /etc/services
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcUnixUdpBridge();
void checkAndSetClientAddress(sockaddr_in& clientAddress);
void setClientAddressToAny(bool ipAddrAnySet);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
int serverSocket = 0;
const int serverSocketOptions = 0;
struct sockaddr_in clientAddress;
socklen_t clientAddressLen = 0;
struct sockaddr_in serverAddress;
socklen_t serverAddressLen = 0;
bool ipAddrAnySet = false;
//! Access to the client address is mutex protected as it is set
//! by another task.
MutexIF* mutex;
void handleSocketError();
void handleBindError();
void handleSendError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */

108
osal/linux/tcpipHelpers.cpp Normal file
View File

@ -0,0 +1,108 @@
#include "../common/tcpipHelpers.h"
#include "../../tasks/TaskFactory.h"
#include <errno.h>
#include <string>
void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration) {
int errCode = errno;
std::string protocolString;
std::string errorSrcString;
determineErrorStrings(protocol, errorSrc, protocolString, errorSrcString);
std::string infoString;
switch(errCode) {
case(EACCES): {
infoString = "EACCES";
break;
}
case(EINVAL): {
infoString = "EINVAL";
break;
}
case(EAGAIN): {
infoString = "EAGAIN";
break;
}
case(EMFILE): {
infoString = "EMFILE";
break;
}
case(ENFILE): {
infoString = "ENFILE";
break;
}
case(EAFNOSUPPORT): {
infoString = "EAFNOSUPPORT";
break;
}
case(ENOBUFS): {
infoString = "ENOBUFS";
break;
}
case(ENOMEM): {
infoString = "ENOMEM";
break;
}
case(EPROTONOSUPPORT): {
infoString = "EPROTONOSUPPORT";
break;
}
case(EADDRINUSE): {
infoString = "EADDRINUSE";
break;
}
case(EBADF): {
infoString = "EBADF";
break;
}
case(ENOTSOCK): {
infoString = "ENOTSOCK";
break;
}
case(EADDRNOTAVAIL): {
infoString = "EADDRNOTAVAIL";
break;
}
case(EFAULT): {
infoString = "EFAULT";
break;
}
case(ELOOP): {
infoString = "ELOOP";
break;
}
case(ENAMETOOLONG): {
infoString = "ENAMETOOLONG";
break;
}
case(ENOENT): {
infoString = "ENOENT";
break;
}
case(ENOTDIR): {
infoString = "ENOTDIR";
break;
}
case(EROFS): {
infoString = "EROFS";
break;
}
default: {
infoString = "Error code: " + std::to_string(errCode);
}
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
" | " << infoString << std::endl;
#else
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString,
errorSrcString, infoString);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
if(sleepDuration > 0) {
TaskFactory::instance()->delayTask(sleepDuration);
}
}

View File

@ -1,7 +1,7 @@
#include "RtemsBasic.h"
#include "../../timemanager/Clock.h"
#include "../../ipc/MutexHelper.h"
#include "../../ipc/MutexGuard.h"
#include <rtems/score/todimpl.h>
#include <rtems/rtems/clockimpl.h>
@ -183,7 +183,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
MutexHelper helper(timeMutex);
MutexGuard helper(timeMutex);
leapSeconds = leapSeconds_;
@ -196,7 +196,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
MutexHelper helper(timeMutex);
MutexGuard helper(timeMutex);
*leapSeconds_ = leapSeconds;

View File

@ -61,7 +61,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
} else {
//No message was received. Keep lastPartner anyway, I might send something later.
//But still, delete packet content.
memset(message->getData(), 0, message->getMaximumMessageSize());
memset(message->getData(), 0, message->getMaximumDataSize());
}
return convertReturnCode(status);
}

View File

@ -1,11 +1,4 @@
target_sources(${LIB_FSFW_NAME}
PRIVATE
TcWinUdpPollingTask.cpp
TmTcWinUdpBridge.cpp
target_sources(${LIB_FSFW_NAME} PRIVATE
tcpipHelpers.cpp
winTaskHelpers.cpp
)
target_link_libraries(${LIB_FSFW_NAME}
PRIVATE
wsock32
ws2_32
)

View File

@ -1,177 +0,0 @@
#include "TcWinUdpPollingTask.h"
#include "../../globalfunctions/arrayprinter.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <winsock2.h>
#include <windows.h>
TcWinUdpPollingTask::TcWinUdpPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t frameSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
else {
this->frameSize = DEFAULT_MAX_FRAME_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) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
TcWinUdpPollingTask::~TcWinUdpPollingTask() {}
ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
// Poll for new UDP datagrams in permanent loop.
while(true) {
//! Sender Address is cached here.
struct sockaddr_in senderAddress;
int senderAddressSize = sizeof(senderAddress);
ssize_t bytesReceived = recvfrom(serverUdpSocket,
reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
receptionFlags, reinterpret_cast<sockaddr*>(&senderAddress),
&senderAddressSize);
if(bytesReceived == SOCKET_ERROR) {
// handle error
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcWinUdpPollingTask::performOperation: Reception"
" error." << std::endl;
#endif
handleReadError();
continue;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
//sif::debug << "TcWinUdpPollingTask::performOperation: " << bytesReceived
// << " bytes received" << std::endl;
#endif
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->registerCommConnect();
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId,
receptionBuffer.data(), bytesRead);
// arrayprinter::print(receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
"storage failed" << std::endl;
sif::error << "Packet size: " << bytesRead << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Serial Polling: Sending message to queue failed"
<< std::endl;
#endif
tcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t TcWinUdpPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
<< std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<TmTcWinUdpBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
" TMTC bridge object!" << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
}
serverUdpSocket = tmtcBridge->serverSocket;
#if FSFW_CPP_OSTREAM_ENABLED == 1
//sif::info << "TcWinUdpPollingTask::initialize: Server UDP socket "
// << serverUdpSocket << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcWinUdpPollingTask::initializeAfterTaskCreation() {
// Initialize the destination after task creation. This ensures
// that the destination has already been set in the TMTC bridge.
targetTcDestination = tmtcBridge->getRequestQueue();
return HasReturnvaluesIF::RETURN_OK;
}
void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) {
DWORD timeoutMs = timeoutSeconds * 1000.0;
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
if(result == -1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
#endif
}
}
void TcWinUdpPollingTask::handleReadError() {
int error = WSAGetLastError();
switch(error) {
case(WSANOTINITIALISED): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TcWinUdpPollingTask::handleReadError: WSANOTINITIALISED: "
<< "WSAStartup(...) call " << "necessary" << std::endl;
#endif
break;
}
case(WSAEFAULT): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TcWinUdpPollingTask::handleReadError: WSADEFAULT: "
<< "Bad address " << std::endl;
#endif
break;
}
case(WSAEINVAL): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TcWinUdpPollingTask::handleReadError: WSAEINVAL: "
<< "Invalid input parameters. " << std::endl;
#endif
break;
}
default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TcWinUdpPollingTask::handleReadError: Error code: "
<< error << std::endl;
#endif
break;
}
}
// to prevent spam.
Sleep(1000);
}

View File

@ -1,212 +0,0 @@
#include <fsfw/ipc/MutexHelper.h>
#include "TmTcWinUdpBridge.h"
TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId,
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort, uint16_t clientPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
communicationLinkUp = false;
// Initiates Winsock DLL.
WSAData wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge:"
"WSAStartup failed with error: " << err << std::endl;
#endif
return;
}
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
if(serverPort != 0xFFFF) {
setServerPort = serverPort;
}
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
if(clientPort != 0xFFFF) {
setClientPort = clientPort;
}
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(serverSocket == INVALID_SOCKET) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open"
" UDP socket!" << std::endl;
#endif
handleSocketError();
return;
}
serverAddress.sin_family = AF_INET;
// Accept packets from any interface. (potentially insecure).
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(setServerPort);
serverAddressLen = sizeof(serverAddress);
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<const char*>(&serverSocketOptions),
sizeof(serverSocketOptions));
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(setClientPort);
clientAddressLen = sizeof(clientAddress);
int result = bind(serverSocket,
reinterpret_cast<struct sockaddr*>(&serverAddress),
serverAddressLen);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
"local port " << setServerPort << " to server socket!"
<< std::endl;
#endif
handleBindError();
}
}
TmTcWinUdpBridge::~TmTcWinUdpBridge() {
WSACleanup();
}
ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
//clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
//clientAddressLen = sizeof(serverAddress);
// char ipAddress [15];
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
#endif
ssize_t bytesSent = sendto(serverSocket,
reinterpret_cast<const char*>(data), dataLen, flags,
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
if(bytesSent == SOCKET_ERROR) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "TmTcWinUdpBridge::sendTm: Send operation failed."
<< std::endl;
#endif
handleSendError();
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
// " sent." << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK;
}
void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15];
#if FSFW_CPP_OSTREAM_ENABLED == 1
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
#endif
registerCommConnect();
// Set new IP address if it has changed.
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
clientAddressLen = sizeof(clientAddress);
}
}
void TmTcWinUdpBridge::handleSocketError() {
int errCode = WSAGetLastError();
switch(errCode) {
case(WSANOTINITIALISED): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TmTcWinUdpBridge::handleSocketError: WSANOTINITIALISED: "
<< "WSAStartup(...) call necessary" << std::endl;
#endif
break;
}
default: {
/*
https://docs.microsoft.com/en-us/windows/win32/winsock/
windows-sockets-error-codes-2
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TmTcWinUdpBridge::handleSocketError: Error code: "
<< errCode << std::endl;
#endif
break;
}
}
}
void TmTcWinUdpBridge::handleBindError() {
int errCode = WSAGetLastError();
switch(errCode) {
case(WSANOTINITIALISED): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TmTcWinUdpBridge::handleBindError: WSANOTINITIALISED: "
<< "WSAStartup(...) call " << "necessary" << std::endl;
#endif
break;
}
case(WSAEADDRINUSE): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcWinUdpBridge::handleBindError: WSAEADDRINUSE: "
<< "Port is already in use!" << std::endl;
#endif
break;
}
default: {
/*
https://docs.microsoft.com/en-us/windows/win32/winsock/
windows-sockets-error-codes-2
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TmTcWinUdpBridge::handleBindError: Error code: "
<< errCode << std::endl;
#endif
break;
}
}
}
void TmTcWinUdpBridge::handleSendError() {
int errCode = WSAGetLastError();
switch(errCode) {
case(WSANOTINITIALISED): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TmTcWinUdpBridge::handleSendError: WSANOTINITIALISED: "
<< "WSAStartup(...) call necessary" << std::endl;
#endif
break;
}
case(WSAEADDRNOTAVAIL): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TmTcWinUdpBridge::handleSendError: WSAEADDRNOTAVAIL: "
<< "Check target address. " << std::endl;
#endif
break;
}
default: {
/*
https://docs.microsoft.com/en-us/windows/win32/winsock/
windows-sockets-error-codes-2
*/
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "TmTcWinUdpBridge::handleSendError: Error code: "
<< errCode << std::endl;
#endif
break;
}
}
}

View File

@ -1,49 +0,0 @@
#ifndef FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
#define FSFW_OSAL_WINDOWS_TMTCWINUDPBRIDGE_H_
#include "../../tmtcservices/TmTcBridge.h"
#include <winsock2.h>
#include <windows.h>
class TmTcWinUdpBridge: public TmTcBridge {
friend class TcWinUdpPollingTask;
public:
// The ports chosen here should not be used by any other process.
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcWinUdpBridge();
void checkAndSetClientAddress(sockaddr_in clientAddress);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
SOCKET serverSocket = 0;
const int serverSocketOptions = 0;
struct sockaddr_in clientAddress;
int clientAddressLen = 0;
struct sockaddr_in serverAddress;
int serverAddressLen = 0;
//! Access to the client address is mutex protected as it is set
//! by another task.
MutexIF* mutex;
void handleSocketError();
void handleBindError();
void handleSendError();
};
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */

View File

@ -0,0 +1,63 @@
#include "../common/tcpipHelpers.h"
#include <FSFWConfig.h>
#include "../../tasks/TaskFactory.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <winsock2.h>
#include <string>
void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration) {
#if FSFW_VERBOSE_LEVEL >= 1
int errCode = WSAGetLastError();
std::string protocolString;
std::string errorSrcString;
determineErrorStrings(protocol, errorSrc, protocolString, errorSrcString);
std::string infoString;
switch(errCode) {
case(WSANOTINITIALISED): {
infoString = "WSANOTINITIALISED";
break;
}
case(WSAEADDRINUSE): {
infoString = "WSAEADDRINUSE";
break;
}
case(WSAEFAULT): {
infoString = "WSAEFAULT";
break;
}
case(WSAEADDRNOTAVAIL): {
infoString = "WSAEADDRNOTAVAIL";
break;
}
case(WSAEINVAL): {
infoString = "WSAEINVAL";
break;
}
default: {
/*
https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
*/
infoString = "Error code: " + std::to_string(errCode);
break;
}
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
" | " << infoString << std::endl;
#else
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString,
errorSrcString, infoString);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
if(sleepDuration > 0) {
TaskFactory::instance()->delayTask(sleepDuration);
}
}

View File

@ -0,0 +1,107 @@
#include <fsfw/osal/windows/winTaskHelpers.h>
#include <mutex>
TaskPriority tasks::makeWinPriority(PriorityClass prioClass, PriorityNumber prioNumber) {
return (static_cast<uint16_t>(prioClass) << 16) | static_cast<uint16_t> (prioNumber);
}
void tasks::getWinPriorityParameters(TaskPriority priority,
DWORD& priorityClass, int& priorityNumber) {
PriorityClass classInternal = static_cast<PriorityClass>(priority >> 16 & 0xff);
PriorityNumber numberInternal = static_cast<PriorityNumber>(priority & 0xff);
switch(classInternal) {
case(CLASS_IDLE): {
priorityClass = IDLE_PRIORITY_CLASS;
break;
}
case(CLASS_BELOW_NORMAL): {
priorityClass = BELOW_NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_NORMAL): {
priorityClass = NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_ABOVE_NORMAL): {
priorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
break;
}
case(CLASS_HIGH): {
priorityClass = HIGH_PRIORITY_CLASS;
break;
}
case(CLASS_REALTIME): {
priorityClass = REALTIME_PRIORITY_CLASS;
break;
}
default: {
priorityClass = NORMAL_PRIORITY_CLASS;
}
}
switch(numberInternal) {
case(IDLE): {
priorityNumber = THREAD_PRIORITY_IDLE;
break;
}
case(LOWEST): {
priorityNumber = THREAD_PRIORITY_LOWEST;
break;
}
case(BELOW_NORMAL): {
priorityNumber = THREAD_PRIORITY_BELOW_NORMAL;
break;
}
case(NORMAL): {
priorityNumber = THREAD_PRIORITY_NORMAL;
break;
}
case(ABOVE_NORMAL): {
priorityNumber = THREAD_PRIORITY_ABOVE_NORMAL;
break;
}
case(HIGHEST): {
priorityNumber = THREAD_PRIORITY_HIGHEST;
break;
}
case(CRITICAL): {
priorityNumber = THREAD_PRIORITY_TIME_CRITICAL;
break;
}
default: {
priorityNumber = THREAD_PRIORITY_NORMAL;
}
}
}
ReturnValue_t tasks::setTaskPriority(HANDLE nativeHandle, TaskPriority priority) {
/* List of possible priority classes:
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setpriorityclass
And respective thread priority numbers:
https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
*/
DWORD dwPriorityClass = 0;
int nPriorityNumber = 0;
tasks::getWinPriorityParameters(priority, dwPriorityClass, nPriorityNumber);
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(nativeHandle),
dwPriorityClass);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(nativeHandle),
nPriorityNumber);
if(result != 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,37 @@
#include "../../tasks/TaskFactory.h"
#include <thread>
#include <map>
#ifdef _WIN32
namespace tasks {
enum PriorityClass: uint16_t {
CLASS_IDLE,
CLASS_BELOW_NORMAL,
CLASS_NORMAL,
CLASS_ABOVE_NORMAL,
CLASS_HIGH,
CLASS_REALTIME
};
enum PriorityNumber: uint16_t {
IDLE,
LOWEST,
BELOW_NORMAL,
NORMAL,
ABOVE_NORMAL,
HIGHEST,
CRITICAL
};
TaskPriority makeWinPriority(PriorityClass prioClass = PriorityClass::CLASS_NORMAL,
PriorityNumber prioNumber = PriorityNumber::NORMAL);
void getWinPriorityParameters(TaskPriority priority, DWORD& priorityClass,
int& priorityNumber);
ReturnValue_t setTaskPriority(HANDLE nativeHandle, TaskPriority priority);
}
#endif