Merge remote-tracking branch 'origin/development' into gaisser_make_linux_realtime_optional
This commit is contained in:
@ -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)
|
@ -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;
|
||||
|
@ -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);
|
||||
|
16
osal/common/CMakeLists.txt
Normal file
16
osal/common/CMakeLists.txt
Normal 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
54
osal/common/TcpIpBase.cpp
Normal 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
50
osal/common/TcpIpBase.h
Normal 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_ */
|
132
osal/common/TcpTmTcServer.cpp
Normal file
132
osal/common/TcpTmTcServer.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
53
osal/common/TcpTmTcServer.h
Normal file
53
osal/common/TcpTmTcServer.h
Normal 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_ */
|
177
osal/common/UdpTcPollingTask.cpp
Normal file
177
osal/common/UdpTcPollingTask.cpp
Normal 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
|
||||
}
|
@ -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_ */
|
172
osal/common/UdpTmTcBridge.cpp
Normal file
172
osal/common/UdpTmTcBridge.cpp
Normal 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;
|
||||
}
|
60
osal/common/UdpTmTcBridge.h
Normal file
60
osal/common/UdpTmTcBridge.h
Normal 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_ */
|
||||
|
36
osal/common/tcpipCommon.cpp
Normal file
36
osal/common/tcpipCommon.cpp
Normal 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
35
osal/common/tcpipCommon.h
Normal 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_ */
|
15
osal/common/tcpipHelpers.h
Normal file
15
osal/common/tcpipHelpers.h
Normal 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_ */
|
@ -10,6 +10,7 @@ target_sources(${LIB_FSFW_NAME}
|
||||
QueueMapManager.cpp
|
||||
SemaphoreFactory.cpp
|
||||
TaskFactory.cpp
|
||||
taskHelpers.cpp
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -24,5 +24,7 @@ MutexIF* MutexFactory::createMutex() {
|
||||
}
|
||||
|
||||
void MutexFactory::deleteMutex(MutexIF* mutex) {
|
||||
delete mutex;
|
||||
if(mutex != nullptr) {
|
||||
delete mutex;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -36,6 +36,8 @@ public:
|
||||
private:
|
||||
//! External instantiation is forbidden.
|
||||
QueueMapManager();
|
||||
~QueueMapManager();
|
||||
|
||||
uint32_t queueCounter = 0;
|
||||
MutexIF* mapLock;
|
||||
QueueMap queueMap;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
27
osal/host/taskHelpers.cpp
Normal 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
16
osal/host/taskHelpers.h
Normal 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_ */
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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?
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
|
@ -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
108
osal/linux/tcpipHelpers.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
)
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
63
osal/windows/tcpipHelpers.cpp
Normal file
63
osal/windows/tcpipHelpers.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
107
osal/windows/winTaskHelpers.cpp
Normal file
107
osal/windows/winTaskHelpers.cpp
Normal 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;
|
||||
}
|
37
osal/windows/winTaskHelpers.h
Normal file
37
osal/windows/winTaskHelpers.h
Normal 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
|
||||
|
Reference in New Issue
Block a user