Merge branch 'development' into gaisser_compiler_flags
This commit is contained in:
commit
68ca6fd122
11
CHANGELOG.md
11
CHANGELOG.md
@ -8,6 +8,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
# [unreleased]
|
# [unreleased]
|
||||||
|
|
||||||
|
# [v5.0.0]
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|
||||||
|
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
|
||||||
|
datapools have been implemented
|
||||||
|
|
||||||
|
## Additions
|
||||||
|
|
||||||
|
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
||||||
|
|
||||||
# [v4.0.0]
|
# [v4.0.0]
|
||||||
|
|
||||||
## Additions
|
## Additions
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
#include "fsfw_hal/linux/i2c/I2cComIF.h"
|
#include "I2cComIF.h"
|
||||||
|
|
||||||
|
#include "fsfw/FSFW.h"
|
||||||
|
#include "fsfw/serviceinterface.h"
|
||||||
|
#include "fsfw_hal/linux/UnixFileGuard.h"
|
||||||
|
#include "fsfw_hal/linux/utility.h"
|
||||||
|
|
||||||
|
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||||
|
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -8,11 +17,6 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "fsfw/FSFW.h"
|
|
||||||
#include "fsfw/serviceinterface.h"
|
|
||||||
#include "fsfw_hal/linux/UnixFileGuard.h"
|
|
||||||
#include "fsfw_hal/linux/utility.h"
|
|
||||||
|
|
||||||
I2cComIF::I2cComIF(object_id_t objectId) : SystemObject(objectId) {}
|
I2cComIF::I2cComIF(object_id_t objectId) : SystemObject(objectId) {}
|
||||||
|
|
||||||
I2cComIF::~I2cComIF() {}
|
I2cComIF::~I2cComIF() {}
|
||||||
@ -112,6 +116,11 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
|
|||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||||
|
sif::info << "Sent I2C data to bus " << deviceFile << ":" << std::endl;
|
||||||
|
arrayprinter::print(sendData, sendLen);
|
||||||
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +185,11 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
|||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||||
|
sif::info << "I2C read bytes from bus " << deviceFile << ":" << std::endl;
|
||||||
|
arrayprinter::print(replyBuffer, requestLen);
|
||||||
|
#endif
|
||||||
|
|
||||||
i2cDeviceMapIter->second.replyLen = requestLen;
|
i2cDeviceMapIter->second.replyLen = requestLen;
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
@ -97,11 +97,11 @@ def handle_docs_type(args, build_dir_list: list):
|
|||||||
build_directory = determine_build_dir(build_dir_list)
|
build_directory = determine_build_dir(build_dir_list)
|
||||||
os.chdir(build_directory)
|
os.chdir(build_directory)
|
||||||
if args.build:
|
if args.build:
|
||||||
os.system("cmake --build . -j")
|
cmd_runner("cmake --build . -j")
|
||||||
if args.open:
|
if args.open:
|
||||||
if not os.path.isfile("docs/sphinx/index.html"):
|
if not os.path.isfile("docs/sphinx/index.html"):
|
||||||
# try again..
|
# try again..
|
||||||
os.system("cmake --build . -j")
|
cmd_runner("cmake --build . -j")
|
||||||
if not os.path.isfile("docs/sphinx/index.html"):
|
if not os.path.isfile("docs/sphinx/index.html"):
|
||||||
print(
|
print(
|
||||||
"No Sphinx documentation file detected. "
|
"No Sphinx documentation file detected. "
|
||||||
@ -143,25 +143,21 @@ def handle_tests_type(args, build_dir_list: list):
|
|||||||
if which("valgrind") is None:
|
if which("valgrind") is None:
|
||||||
print("Please install valgrind first")
|
print("Please install valgrind first")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.split(os.getcwd())[1] != UNITTEST_FOLDER_NAME:
|
cmd_runner("valgrind --leak-check=full ./fsfw-tests")
|
||||||
# If we are in a different directory we try to switch into it but
|
|
||||||
# this might fail
|
|
||||||
os.chdir(UNITTEST_FOLDER_NAME)
|
|
||||||
os.system("valgrind --leak-check=full ./fsfw-tests")
|
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
def create_tests_build_cfg():
|
def create_tests_build_cfg():
|
||||||
os.mkdir(UNITTEST_FOLDER_NAME)
|
os.mkdir(UNITTEST_FOLDER_NAME)
|
||||||
os.chdir(UNITTEST_FOLDER_NAME)
|
os.chdir(UNITTEST_FOLDER_NAME)
|
||||||
os.system("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..")
|
cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..")
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
def create_docs_build_cfg():
|
def create_docs_build_cfg():
|
||||||
os.mkdir(DOCS_FOLDER_NAME)
|
os.mkdir(DOCS_FOLDER_NAME)
|
||||||
os.chdir(DOCS_FOLDER_NAME)
|
os.chdir(DOCS_FOLDER_NAME)
|
||||||
os.system("cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..")
|
cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..")
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
@ -184,7 +180,7 @@ def check_for_cmake_build_dir(build_dir_list: list) -> list:
|
|||||||
def perform_lcov_operation(directory: str, chdir: bool):
|
def perform_lcov_operation(directory: str, chdir: bool):
|
||||||
if chdir:
|
if chdir:
|
||||||
os.chdir(directory)
|
os.chdir(directory)
|
||||||
os.system("cmake --build . -- fsfw-tests_coverage -j")
|
cmd_runner("cmake --build . -- fsfw-tests_coverage -j")
|
||||||
|
|
||||||
|
|
||||||
def determine_build_dir(build_dir_list: List[str]):
|
def determine_build_dir(build_dir_list: List[str]):
|
||||||
@ -206,5 +202,10 @@ def determine_build_dir(build_dir_list: List[str]):
|
|||||||
return build_directory
|
return build_directory
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_runner(cmd: str):
|
||||||
|
print(f"Executing command: {cmd}")
|
||||||
|
os.system(cmd)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -69,4 +69,9 @@
|
|||||||
#define FSFW_HAL_LIS3MDL_MGM_DEBUG 0
|
#define FSFW_HAL_LIS3MDL_MGM_DEBUG 0
|
||||||
#endif /* FSFW_HAL_LIS3MDL_MGM_DEBUG */
|
#endif /* FSFW_HAL_LIS3MDL_MGM_DEBUG */
|
||||||
|
|
||||||
|
// Can be used for low-level debugging of the I2C bus
|
||||||
|
#ifndef FSFW_HAL_I2C_WIRETAPPING
|
||||||
|
#define FSFW_HAL_I2C_WIRETAPPING 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* FSFW_FSFW_H_ */
|
#endif /* FSFW_FSFW_H_ */
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
|
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
|
||||||
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
|
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
|
||||||
|
|
||||||
#include "fsfw/datapool/HkSwitchHelper.h"
|
|
||||||
#include "fsfw/health/HasHealthIF.h"
|
#include "fsfw/health/HasHealthIF.h"
|
||||||
#include "fsfw/health/HealthHelper.h"
|
#include "fsfw/health/HealthHelper.h"
|
||||||
#include "fsfw/modes/HasModesIF.h"
|
#include "fsfw/modes/HasModesIF.h"
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
PRIVATE
|
|
||||||
HkSwitchHelper.cpp
|
|
||||||
PoolDataSetBase.cpp
|
PoolDataSetBase.cpp
|
||||||
PoolEntry.cpp
|
PoolEntry.cpp
|
||||||
)
|
)
|
@ -1,67 +0,0 @@
|
|||||||
#include "fsfw/datapool/HkSwitchHelper.h"
|
|
||||||
|
|
||||||
#include "fsfw/ipc/QueueFactory.h"
|
|
||||||
|
|
||||||
HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy)
|
|
||||||
: commandActionHelper(this), eventProxy(eventProxy) {
|
|
||||||
actionQueue = QueueFactory::instance()->createMessageQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
HkSwitchHelper::~HkSwitchHelper() { QueueFactory::instance()->deleteMessageQueue(actionQueue); }
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::initialize() {
|
|
||||||
ReturnValue_t result = commandActionHelper.initialize();
|
|
||||||
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) {
|
|
||||||
CommandMessage command;
|
|
||||||
while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
ReturnValue_t result = commandActionHelper.handleReply(&command);
|
|
||||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
command.setToUnknownCommand();
|
|
||||||
actionQueue->reply(&command);
|
|
||||||
}
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {}
|
|
||||||
|
|
||||||
void HkSwitchHelper::stepFailedReceived(ActionId_t actionId, uint8_t step,
|
|
||||||
ReturnValue_t returnCode) {
|
|
||||||
eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) {}
|
|
||||||
|
|
||||||
void HkSwitchHelper::completionSuccessfulReceived(ActionId_t actionId) {}
|
|
||||||
|
|
||||||
void HkSwitchHelper::completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) {
|
|
||||||
eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::switchHK(SerializeIF* sids, bool enable) {
|
|
||||||
// ActionId_t action = HKService::DISABLE_HK;
|
|
||||||
// if (enable) {
|
|
||||||
// action = HKService::ENABLE_HK;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ReturnValue_t result = commandActionHelper.commandAction(
|
|
||||||
// objects::PUS_HK_SERVICE, action, sids);
|
|
||||||
//
|
|
||||||
// if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
// eventProxy->forwardEvent(SWITCHING_TM_FAILED, result);
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueIF* HkSwitchHelper::getCommandQueuePtr() { return actionQueue; }
|
|
@ -1,44 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
|
|
||||||
#define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
|
|
||||||
|
|
||||||
#include "fsfw/action/CommandsActionsIF.h"
|
|
||||||
#include "fsfw/events/EventReportingProxyIF.h"
|
|
||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
|
||||||
|
|
||||||
// TODO this class violations separation between mission and framework
|
|
||||||
// but it is only a transitional solution until the Datapool is
|
|
||||||
// implemented decentrally
|
|
||||||
|
|
||||||
class HkSwitchHelper : public ExecutableObjectIF, public CommandsActionsIF {
|
|
||||||
public:
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK;
|
|
||||||
static const Event SWITCHING_TM_FAILED =
|
|
||||||
MAKE_EVENT(1, severity::LOW); //!< Commanding the HK Service failed, p1: error code, p2
|
|
||||||
//!< action: 0 disable / 1 enable
|
|
||||||
|
|
||||||
HkSwitchHelper(EventReportingProxyIF* eventProxy);
|
|
||||||
virtual ~HkSwitchHelper();
|
|
||||||
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
|
|
||||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0);
|
|
||||||
|
|
||||||
ReturnValue_t switchHK(SerializeIF* sids, bool enable);
|
|
||||||
|
|
||||||
virtual void setTaskIF(PeriodicTaskIF* task_){};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step);
|
|
||||||
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode);
|
|
||||||
virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size);
|
|
||||||
virtual void completionSuccessfulReceived(ActionId_t actionId);
|
|
||||||
virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode);
|
|
||||||
virtual MessageQueueIF* getCommandQueuePtr();
|
|
||||||
|
|
||||||
private:
|
|
||||||
CommandActionHelper commandActionHelper;
|
|
||||||
MessageQueueIF* actionQueue;
|
|
||||||
EventReportingProxyIF* eventProxy;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ */
|
|
@ -84,8 +84,8 @@ ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "initialize", HasReturnvaluesIF::RETURN_FAILED,
|
printWarningOrError(sif::OutputTypes::OUT_WARNING, "initializeHousekeepingPoolEntriesOnce",
|
||||||
"The map should only be initialized once");
|
HasReturnvaluesIF::RETURN_FAILED, "The map should only be initialized once");
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,9 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
|||||||
internalErrorDataset.storeHits.value += newStoreHits;
|
internalErrorDataset.storeHits.value += newStoreHits;
|
||||||
internalErrorDataset.tmHits.value += newTmHits;
|
internalErrorDataset.tmHits.value += newTmHits;
|
||||||
internalErrorDataset.setValidity(true, true);
|
internalErrorDataset.setValidity(true, true);
|
||||||
|
if ((newQueueHits != 0) or (newStoreHits != 0) or (newTmHits != 0)) {
|
||||||
|
internalErrorDataset.setChanged(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,14 +80,6 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t InternalErrorReporter::getQueueHits() {
|
|
||||||
uint32_t value;
|
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
|
||||||
value = queueHits;
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InternalErrorReporter::incrementQueueHits() {
|
void InternalErrorReporter::incrementQueueHits() {
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
mutex->lockMutex(timeoutType, timeoutMs);
|
||||||
queueHits++;
|
queueHits++;
|
||||||
@ -100,14 +95,6 @@ uint32_t InternalErrorReporter::getAndResetTmHits() {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t InternalErrorReporter::getTmHits() {
|
|
||||||
uint32_t value;
|
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
|
||||||
value = tmHits;
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InternalErrorReporter::incrementTmHits() {
|
void InternalErrorReporter::incrementTmHits() {
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
mutex->lockMutex(timeoutType, timeoutMs);
|
||||||
tmHits++;
|
tmHits++;
|
||||||
@ -125,14 +112,6 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t InternalErrorReporter::getStoreHits() {
|
|
||||||
uint32_t value;
|
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
|
||||||
value = storeHits;
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InternalErrorReporter::incrementStoreHits() {
|
void InternalErrorReporter::incrementStoreHits() {
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
mutex->lockMutex(timeoutType, timeoutMs);
|
||||||
storeHits++;
|
storeHits++;
|
||||||
|
@ -46,11 +46,11 @@ class InternalErrorReporter : public SystemObject,
|
|||||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
|
||||||
virtual void queueMessageNotSent();
|
virtual void queueMessageNotSent() override;
|
||||||
|
|
||||||
virtual void lostTm();
|
virtual void lostTm() override;
|
||||||
|
|
||||||
virtual void storeFull();
|
virtual void storeFull() override;
|
||||||
|
|
||||||
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
||||||
|
|
||||||
@ -74,15 +74,12 @@ class InternalErrorReporter : public SystemObject,
|
|||||||
uint32_t storeHits = 0;
|
uint32_t storeHits = 0;
|
||||||
|
|
||||||
uint32_t getAndResetQueueHits();
|
uint32_t getAndResetQueueHits();
|
||||||
uint32_t getQueueHits();
|
|
||||||
void incrementQueueHits();
|
void incrementQueueHits();
|
||||||
|
|
||||||
uint32_t getAndResetTmHits();
|
uint32_t getAndResetTmHits();
|
||||||
uint32_t getTmHits();
|
|
||||||
void incrementTmHits();
|
void incrementTmHits();
|
||||||
|
|
||||||
uint32_t getAndResetStoreHits();
|
uint32_t getAndResetStoreHits();
|
||||||
uint32_t getStoreHits();
|
|
||||||
void incrementStoreHits();
|
void incrementStoreHits();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,22 +1,34 @@
|
|||||||
#ifndef INTERNALERRORREPORTERIF_H_
|
#ifndef INTERNALERRORREPORTERIF_H_
|
||||||
#define INTERNALERRORREPORTERIF_H_
|
#define INTERNALERRORREPORTERIF_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interface which is used to report internal errors like full message queues or stores.
|
||||||
|
* @details
|
||||||
|
* This interface smust be used for the InteralErrorReporter object.
|
||||||
|
* It should be used to indicate that there was a Problem with Queues or Stores.
|
||||||
|
*
|
||||||
|
* It can be used to report missing Telemetry which could not be sent due to a internal problem.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class InternalErrorReporterIF {
|
class InternalErrorReporterIF {
|
||||||
public:
|
public:
|
||||||
virtual ~InternalErrorReporterIF() {}
|
virtual ~InternalErrorReporterIF() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread safe
|
* @brief Function to be called if a message queue could not be sent.
|
||||||
|
* @details OSAL Implementations should call this function to indicate that
|
||||||
|
* a message was lost.
|
||||||
|
*
|
||||||
|
* Implementations are required to be Thread safe
|
||||||
*/
|
*/
|
||||||
virtual void queueMessageNotSent() = 0;
|
virtual void queueMessageNotSent() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread safe
|
* @brief Function to be called if Telemetry could not be sent
|
||||||
|
* @details Implementations must be Thread safe
|
||||||
*/
|
*/
|
||||||
virtual void lostTm() = 0;
|
virtual void lostTm() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread safe
|
* @brief Function to be called if a onboard storage is full
|
||||||
|
* @details Implementations must be Thread safe
|
||||||
*/
|
*/
|
||||||
virtual void storeFull() = 0;
|
virtual void storeFull() = 0;
|
||||||
};
|
};
|
||||||
|
@ -125,6 +125,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(),
|
memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(),
|
||||||
message->getMaximumMessageSize());
|
message->getMaximumMessageSize());
|
||||||
} else {
|
} else {
|
||||||
|
if (not ignoreFault) {
|
||||||
|
InternalErrorReporterIF* internalErrorReporter =
|
||||||
|
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
if (internalErrorReporter != nullptr) {
|
||||||
|
internalErrorReporter->queueMessageNotSent();
|
||||||
|
}
|
||||||
|
}
|
||||||
return MessageQueueIF::FULL;
|
return MessageQueueIF::FULL;
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
@ -23,3 +23,4 @@ add_subdirectory(timemanager)
|
|||||||
add_subdirectory(tmtcpacket)
|
add_subdirectory(tmtcpacket)
|
||||||
add_subdirectory(cfdp)
|
add_subdirectory(cfdp)
|
||||||
add_subdirectory(hal)
|
add_subdirectory(hal)
|
||||||
|
add_subdirectory(internalerror)
|
||||||
|
3
tests/src/fsfw_tests/unit/internalerror/CMakeLists.txt
Normal file
3
tests/src/fsfw_tests/unit/internalerror/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||||
|
TestInternalErrorReporter.cpp
|
||||||
|
)
|
@ -0,0 +1,118 @@
|
|||||||
|
#include <fsfw/housekeeping/HousekeepingSnapshot.h>
|
||||||
|
#include <fsfw/internalerror/InternalErrorReporter.h>
|
||||||
|
#include <fsfw/ipc/MessageQueueIF.h>
|
||||||
|
#include <fsfw/ipc/QueueFactory.h>
|
||||||
|
#include <fsfw/objectmanager/ObjectManager.h>
|
||||||
|
#include <fsfw/timemanager/CCSDSTime.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include "fsfw/action/ActionMessage.h"
|
||||||
|
#include "fsfw/ipc/CommandMessage.h"
|
||||||
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
|
#include "fsfw/objectmanager/frameworkObjects.h"
|
||||||
|
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||||
|
#include "fsfw_tests/unit/mocks/PeriodicTaskIFMock.h"
|
||||||
|
|
||||||
|
TEST_CASE("Internal Error Reporter", "[TestInternalError]") {
|
||||||
|
PeriodicTaskMock task(10);
|
||||||
|
ObjectManagerIF* manager = ObjectManager::instance();
|
||||||
|
if (manager == nullptr) {
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
InternalErrorReporter* internalErrorReporter = dynamic_cast<InternalErrorReporter*>(
|
||||||
|
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER));
|
||||||
|
if (internalErrorReporter == nullptr) {
|
||||||
|
FAIL();
|
||||||
|
}
|
||||||
|
task.addComponent(objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
MessageQueueIF* testQueue = QueueFactory::instance()->createMessageQueue(1);
|
||||||
|
MessageQueueIF* hkQueue = QueueFactory::instance()->createMessageQueue(1);
|
||||||
|
internalErrorReporter->getSubscriptionInterface()->subscribeForSetUpdateMessage(
|
||||||
|
InternalErrorDataset::ERROR_SET_ID, objects::NO_OBJECT, hkQueue->getId(), true);
|
||||||
|
StorageManagerIF* ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||||
|
SECTION("MessageQueueFull") {
|
||||||
|
CommandMessage message;
|
||||||
|
ActionMessage::setCompletionReply(&message, 10, true);
|
||||||
|
auto result = hkQueue->sendMessage(testQueue->getId(), &message);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
uint32_t queueHits = 0;
|
||||||
|
uint32_t lostTm = 0;
|
||||||
|
uint32_t storeHits = 0;
|
||||||
|
/* We don't know if another test caused a queue Hit so we will enforce one,
|
||||||
|
then remeber the queueHit count and force another hit */
|
||||||
|
internalErrorReporter->queueMessageNotSent();
|
||||||
|
internalErrorReporter->performOperation(0);
|
||||||
|
{
|
||||||
|
CommandMessage hkMessage;
|
||||||
|
result = hkQueue->receiveMessage(&hkMessage);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
REQUIRE(hkMessage.getCommand() == HousekeepingMessage::UPDATE_SNAPSHOT_SET);
|
||||||
|
store_address_t storeAddress;
|
||||||
|
gp_id_t gpid =
|
||||||
|
HousekeepingMessage::getUpdateSnapshotVariableCommand(&hkMessage, &storeAddress);
|
||||||
|
REQUIRE(gpid.objectId == objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
// We need the object ID of the reporter here (NO_OBJECT)
|
||||||
|
InternalErrorDataset dataset(objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
CCSDSTime::CDS_short time;
|
||||||
|
ConstAccessorPair data = ipcStore->getData(storeAddress);
|
||||||
|
REQUIRE(data.first == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
HousekeepingSnapshot hkSnapshot(&time, &dataset);
|
||||||
|
const uint8_t* buffer = data.second.data();
|
||||||
|
size_t size = data.second.size();
|
||||||
|
result = hkSnapshot.deSerialize(&buffer, &size, SerializeIF::Endianness::MACHINE);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
// Remember the amount of queueHits before to see the increase
|
||||||
|
queueHits = dataset.queueHits.value;
|
||||||
|
lostTm = dataset.tmHits.value;
|
||||||
|
storeHits = dataset.storeHits.value;
|
||||||
|
}
|
||||||
|
result = hkQueue->sendMessage(testQueue->getId(), &message);
|
||||||
|
REQUIRE(result == MessageQueueIF::FULL);
|
||||||
|
internalErrorReporter->lostTm();
|
||||||
|
internalErrorReporter->storeFull();
|
||||||
|
{
|
||||||
|
internalErrorReporter->performOperation(0);
|
||||||
|
CommandMessage hkMessage;
|
||||||
|
result = hkQueue->receiveMessage(&hkMessage);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
REQUIRE(hkMessage.getCommand() == HousekeepingMessage::UPDATE_SNAPSHOT_SET);
|
||||||
|
store_address_t storeAddress;
|
||||||
|
gp_id_t gpid =
|
||||||
|
HousekeepingMessage::getUpdateSnapshotVariableCommand(&hkMessage, &storeAddress);
|
||||||
|
REQUIRE(gpid.objectId == objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
|
||||||
|
ConstAccessorPair data = ipcStore->getData(storeAddress);
|
||||||
|
REQUIRE(data.first == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
CCSDSTime::CDS_short time;
|
||||||
|
// We need the object ID of the reporter here (NO_OBJECT)
|
||||||
|
InternalErrorDataset dataset(objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
HousekeepingSnapshot hkSnapshot(&time, &dataset);
|
||||||
|
const uint8_t* buffer = data.second.data();
|
||||||
|
size_t size = data.second.size();
|
||||||
|
result = hkSnapshot.deSerialize(&buffer, &size, SerializeIF::Endianness::MACHINE);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
// Test that we had one more queueHit
|
||||||
|
REQUIRE(dataset.queueHits.value == (queueHits + 1));
|
||||||
|
REQUIRE(dataset.tmHits.value == (lostTm + 1));
|
||||||
|
REQUIRE(dataset.storeHits.value == (storeHits + 1));
|
||||||
|
}
|
||||||
|
// Complete Coverage
|
||||||
|
internalErrorReporter->setDiagnosticPrintout(true);
|
||||||
|
internalErrorReporter->setMutexTimeout(MutexIF::TimeoutType::BLOCKING, 0);
|
||||||
|
{
|
||||||
|
// Message Queue Id
|
||||||
|
MessageQueueId_t id = internalErrorReporter->getCommandQueue();
|
||||||
|
REQUIRE(id != MessageQueueIF::NO_QUEUE);
|
||||||
|
CommandMessage message;
|
||||||
|
sid_t sid(objects::INTERNAL_ERROR_REPORTER, InternalErrorDataset::ERROR_SET_ID);
|
||||||
|
HousekeepingMessage::setToggleReportingCommand(&message, sid, true, false);
|
||||||
|
result = hkQueue->sendMessage(id, &message);
|
||||||
|
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||||
|
internalErrorReporter->performOperation(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QueueFactory::instance()->deleteMessageQueue(testQueue);
|
||||||
|
QueueFactory::instance()->deleteMessageQueue(hkQueue);
|
||||||
|
}
|
37
tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h
Normal file
37
tests/src/fsfw_tests/unit/mocks/PeriodicTaskIFMock.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_
|
||||||
|
#define FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_
|
||||||
|
|
||||||
|
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||||
|
#include <fsfw/tasks/PeriodicTaskIF.h>
|
||||||
|
|
||||||
|
class PeriodicTaskMock : public PeriodicTaskIF {
|
||||||
|
public:
|
||||||
|
PeriodicTaskMock(uint32_t period = 5) : period(period) {}
|
||||||
|
/**
|
||||||
|
* @brief A virtual destructor as it is mandatory for interfaces.
|
||||||
|
*/
|
||||||
|
virtual ~PeriodicTaskMock() {}
|
||||||
|
/**
|
||||||
|
* @brief With the startTask method, a created task can be started
|
||||||
|
* for the first time.
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t startTask() override { return HasReturnvaluesIF::RETURN_OK; };
|
||||||
|
|
||||||
|
virtual ReturnValue_t addComponent(object_id_t object) override {
|
||||||
|
ExecutableObjectIF* executableObject =
|
||||||
|
ObjectManager::instance()->get<ExecutableObjectIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
if (executableObject == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
executableObject->setTaskIF(this);
|
||||||
|
executableObject->initializeAfterTaskCreation();
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ReturnValue_t sleepFor(uint32_t ms) override { return HasReturnvaluesIF::RETURN_OK; };
|
||||||
|
|
||||||
|
virtual uint32_t getPeriodMs() const override { return period; };
|
||||||
|
uint32_t period;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FSFW_UNITTEST_TESTS_MOCKS_PERIODICTASKMOCK_H_
|
@ -35,4 +35,25 @@ TEST_CASE("MessageQueue Basic Test", "[TestMq]") {
|
|||||||
senderId = testReceiverMq->getLastPartner();
|
senderId = testReceiverMq->getLastPartner();
|
||||||
CHECK(senderId == testSenderMqId);
|
CHECK(senderId == testSenderMqId);
|
||||||
}
|
}
|
||||||
|
SECTION("Test Full") {
|
||||||
|
auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||||
|
REQUIRE(result == MessageQueueIF::FULL);
|
||||||
|
// We try another message
|
||||||
|
result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||||
|
REQUIRE(result == MessageQueueIF::FULL);
|
||||||
|
MessageQueueMessage recvMessage;
|
||||||
|
result = testReceiverMq->receiveMessage(&recvMessage);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
CHECK(recvMessage.getData()[0] == 42);
|
||||||
|
result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
result = testReceiverMq->receiveMessage(&recvMessage);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
CHECK(recvMessage.getData()[0] == 42);
|
||||||
|
}
|
||||||
|
// We have to clear MQs ourself ATM
|
||||||
|
QueueFactory::instance()->deleteMessageQueue(testSenderMq);
|
||||||
|
QueueFactory::instance()->deleteMessageQueue(testReceiverMq);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user