Merge branch 'development' into mueller/possible-ring-buffer-fix
This commit is contained in:
commit
4da18172b3
@ -1,7 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="fsfw-tests_coverage" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="fsfw-tests" TARGET_NAME="fsfw-tests_coverage" CONFIG_NAME="Debug Unittest" RUN_TARGET_PROJECT_NAME="fsfw-tests" RUN_TARGET_NAME="fsfw-tests">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
@ -1,7 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="fsfw" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="fsfw-tests" TARGET_NAME="fsfw" CONFIG_NAME="Debug Unittest" RUN_TARGET_PROJECT_NAME="fsfw-tests" RUN_TARGET_NAME="fsfw-tests">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
@ -19,12 +19,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
|
||||
compiler supports it
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
|
||||
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
||||
and mode
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
||||
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
|
||||
name clashes with Windows defines.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
||||
@ -123,6 +117,8 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
|
||||
## Additions
|
||||
|
||||
- New constructor for PoolEntry which allows to simply specify the length of the pool entry.
|
||||
This is also the new default constructor for scalar value with 0 as an initial value
|
||||
- Added options for CI/CD builds: `FSFW_CICD_BUILD`. This allows the source code to know
|
||||
whether it is running in CI/CD
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/623
|
||||
|
@ -67,6 +67,7 @@ endif()
|
||||
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
||||
|
||||
set(FSFW_ETL_LIB_NAME etl)
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
set(FSFW_ETL_LIB_MAJOR_VERSION
|
||||
20
|
||||
CACHE STRING "ETL library major version requirement")
|
||||
@ -447,8 +448,8 @@ target_include_directories(
|
||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE ${FSFW_WARNING_FLAGS}
|
||||
${COMPILER_FLAGS})
|
||||
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ETL_LINK_TARGET}
|
||||
${FSFW_ADDITIONAL_LINK_LIBS})
|
||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ADDITIONAL_LINK_LIBS})
|
||||
target_link_libraries(${LIB_FSFW_NAME} PUBLIC ${FSFW_ETL_LINK_TARGET})
|
||||
|
||||
string(
|
||||
CONCAT
|
||||
|
@ -139,7 +139,7 @@ You can also use `-DFSFW_OSAL=linux` on Linux systems.
|
||||
|
||||
Coverage data in HTML format can be generated using the `CodeCoverage`
|
||||
[CMake module](https://github.com/bilke/cmake-modules/tree/master).
|
||||
To build the unittests, run them and then generare the coverage data in this format,
|
||||
To build the unittests, run them and then generate the coverage data in this format,
|
||||
the following command can be used inside the build directory after the build system was set up
|
||||
|
||||
```sh
|
||||
@ -188,7 +188,10 @@ and open the documentation conveniently. Try `helper.py -h for more information.
|
||||
|
||||
The formatting is done by the `clang-format` tool. The configuration is contained within the
|
||||
`.clang-format` file in the repository root. As long as `clang-format` is installed, you
|
||||
can run the `apply-clang-format.sh` helper script to format all source files consistently.
|
||||
can run the `auto-format.sh` helper script to format all source files consistently. Furthermore cmake-format is required to format CMake files which can be installed with:
|
||||
````sh
|
||||
sudo pip install cmakelang
|
||||
````
|
||||
|
||||
## Index
|
||||
|
||||
|
@ -12,3 +12,9 @@ RUN git clone https://github.com/catchorg/Catch2.git && \
|
||||
git checkout v3.0.0-preview5 && \
|
||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
||||
cmake --build build/ --target install
|
||||
|
||||
RUN git clone https://github.com/ETLCPP/etl.git && \
|
||||
cd etl && \
|
||||
git checkout 20.28.0 && \
|
||||
cmake -B build . && \
|
||||
cmake --install build/
|
||||
|
2
automation/Jenkinsfile
vendored
2
automation/Jenkinsfile
vendored
@ -3,7 +3,7 @@ pipeline {
|
||||
BUILDDIR = 'build-tests'
|
||||
}
|
||||
agent {
|
||||
docker { image 'fsfw-ci:d2'}
|
||||
docker { image 'fsfw-ci:d3'}
|
||||
}
|
||||
stages {
|
||||
stage('Clean') {
|
||||
|
@ -48,6 +48,20 @@ def main():
|
||||
action="store_true",
|
||||
help="Run valgrind on generated test binary",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-g",
|
||||
"--generators",
|
||||
default = "Ninja",
|
||||
action="store",
|
||||
help="CMake generators",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-w",
|
||||
"--windows",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Run on windows",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.all:
|
||||
@ -115,14 +129,14 @@ def handle_tests_type(args, build_dir_list: list):
|
||||
if args.create:
|
||||
if os.path.exists(UNITTEST_FOLDER_NAME):
|
||||
shutil.rmtree(UNITTEST_FOLDER_NAME)
|
||||
create_tests_build_cfg()
|
||||
create_tests_build_cfg(args)
|
||||
build_directory = UNITTEST_FOLDER_NAME
|
||||
elif len(build_dir_list) == 0:
|
||||
print(
|
||||
"No valid CMake tests build directory found. "
|
||||
"Trying to set up test build system"
|
||||
)
|
||||
create_tests_build_cfg()
|
||||
create_tests_build_cfg(args)
|
||||
build_directory = UNITTEST_FOLDER_NAME
|
||||
elif len(build_dir_list) == 1:
|
||||
build_directory = build_dir_list[0]
|
||||
@ -147,10 +161,15 @@ def handle_tests_type(args, build_dir_list: list):
|
||||
os.chdir("..")
|
||||
|
||||
|
||||
def create_tests_build_cfg():
|
||||
def create_tests_build_cfg(args):
|
||||
os.mkdir(UNITTEST_FOLDER_NAME)
|
||||
os.chdir(UNITTEST_FOLDER_NAME)
|
||||
cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..")
|
||||
if args.windows:
|
||||
cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON \
|
||||
-DGCOVR_PATH="py -m gcovr" ..'
|
||||
else:
|
||||
cmake_cmd = 'cmake -G "' + args.generators + '" -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..'
|
||||
cmd_runner(cmake_cmd)
|
||||
os.chdir("..")
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
||||
: owner(setOwner), queueToUse(useThisQueue) {}
|
||||
|
||||
ActionHelper::~ActionHelper() {}
|
||||
ActionHelper::~ActionHelper() = default;
|
||||
|
||||
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
|
||||
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
|
||||
@ -59,7 +59,7 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
|
||||
|
||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
store_address_t dataAddress) {
|
||||
const uint8_t* dataPtr = NULL;
|
||||
const uint8_t* dataPtr = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef FSFW_ACTION_ACTIONHELPER_H_
|
||||
#define FSFW_ACTION_ACTIONHELPER_H_
|
||||
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
#include "ActionMessage.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
/**
|
||||
* @brief Action Helper is a helper class which handles action messages
|
||||
*
|
||||
|
@ -2,9 +2,9 @@
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
|
||||
ActionMessage::ActionMessage() {}
|
||||
ActionMessage::ActionMessage() = default;
|
||||
|
||||
ActionMessage::~ActionMessage() {}
|
||||
ActionMessage::~ActionMessage() = default;
|
||||
|
||||
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
|
||||
store_address_t parameters) {
|
||||
@ -64,9 +64,8 @@ void ActionMessage::clear(CommandMessage* message) {
|
||||
switch (message->getCommand()) {
|
||||
case EXECUTE_ACTION:
|
||||
case DATA_REPLY: {
|
||||
StorageManagerIF* ipcStore =
|
||||
ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore != NULL) {
|
||||
auto* ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore != nullptr) {
|
||||
ipcStore->deleteData(getStoreId(message));
|
||||
}
|
||||
break;
|
||||
|
@ -2,14 +2,14 @@
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
|
||||
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner)
|
||||
: owner(setOwner), queueToUse(NULL), ipcStore(NULL), commandCount(0), lastTarget(0) {}
|
||||
: owner(setOwner), queueToUse(nullptr), ipcStore(nullptr), commandCount(0), lastTarget(0) {}
|
||||
|
||||
CommandActionHelper::~CommandActionHelper() {}
|
||||
CommandActionHelper::~CommandActionHelper() = default;
|
||||
|
||||
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
SerializeIF *data) {
|
||||
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == NULL) {
|
||||
auto *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == nullptr) {
|
||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||
}
|
||||
store_address_t storeId;
|
||||
@ -29,11 +29,8 @@ ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId
|
||||
|
||||
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
const uint8_t *data, uint32_t size) {
|
||||
// if (commandCount != 0) {
|
||||
// return CommandsFunctionsIF::ALREADY_COMMANDING;
|
||||
// }
|
||||
HasActionsIF *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == NULL) {
|
||||
auto *receiver = ObjectManager::instance()->get<HasActionsIF>(commandTo);
|
||||
if (receiver == nullptr) {
|
||||
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||
}
|
||||
store_address_t storeId;
|
||||
@ -59,12 +56,12 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, ActionI
|
||||
|
||||
ReturnValue_t CommandActionHelper::initialize() {
|
||||
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
if (ipcStore == NULL) {
|
||||
if (ipcStore == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
|
||||
queueToUse = owner->getCommandQueuePtr();
|
||||
if (queueToUse == NULL) {
|
||||
if (queueToUse == nullptr) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
@ -104,7 +101,7 @@ ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
|
||||
uint8_t CommandActionHelper::getCommandCount() const { return commandCount; }
|
||||
|
||||
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
|
||||
const uint8_t *data = NULL;
|
||||
const uint8_t *data = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
|
@ -14,14 +14,14 @@ class CommandActionHelper {
|
||||
friend class CommandsActionsIF;
|
||||
|
||||
public:
|
||||
CommandActionHelper(CommandsActionsIF* owner);
|
||||
explicit CommandActionHelper(CommandsActionsIF* owner);
|
||||
virtual ~CommandActionHelper();
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
||||
uint32_t size);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t handleReply(CommandMessage* reply);
|
||||
uint8_t getCommandCount() const;
|
||||
[[nodiscard]] uint8_t getCommandCount() const;
|
||||
|
||||
private:
|
||||
CommandsActionsIF* owner;
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
|
||||
#define FSFW_ACTION_COMMANDSACTIONSIF_H_
|
||||
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "CommandActionHelper.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
|
||||
/**
|
||||
* Interface to separate commanding actions of other objects.
|
||||
@ -21,7 +21,7 @@ class CommandsActionsIF {
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::COMMANDS_ACTIONS_IF;
|
||||
static const ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2);
|
||||
virtual ~CommandsActionsIF() {}
|
||||
virtual ~CommandsActionsIF() = default;
|
||||
virtual MessageQueueIF* getCommandQueuePtr() = 0;
|
||||
|
||||
protected:
|
||||
|
@ -1,11 +1,11 @@
|
||||
#ifndef FSFW_ACTION_HASACTIONSIF_H_
|
||||
#define FSFW_ACTION_HASACTIONSIF_H_
|
||||
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "ActionHelper.h"
|
||||
#include "ActionMessage.h"
|
||||
#include "SimpleActionHelper.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
|
||||
/**
|
||||
* @brief
|
||||
@ -40,12 +40,12 @@ class HasActionsIF {
|
||||
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
|
||||
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
|
||||
virtual ~HasActionsIF() {}
|
||||
virtual ~HasActionsIF() = default;
|
||||
/**
|
||||
* Function to get the MessageQueueId_t of the implementing object
|
||||
* @return MessageQueueId_t of the object
|
||||
*/
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
[[nodiscard]] virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
/**
|
||||
* Execute or initialize the execution of a certain function.
|
||||
* The ActionHelpers will execute this function and behave differently
|
||||
|
@ -3,7 +3,7 @@
|
||||
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
||||
: ActionHelper(setOwner, useThisQueue), isExecuting(false) {}
|
||||
|
||||
SimpleActionHelper::~SimpleActionHelper() {}
|
||||
SimpleActionHelper::~SimpleActionHelper() = default;
|
||||
|
||||
void SimpleActionHelper::step(ReturnValue_t result) {
|
||||
// STEP_OFFESET is subtracted to compensate for adding offset in base
|
||||
@ -38,7 +38,7 @@ void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::IS_BUSY);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
}
|
||||
const uint8_t* dataPtr = NULL;
|
||||
const uint8_t* dataPtr = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
|
@ -11,15 +11,15 @@
|
||||
class SimpleActionHelper : public ActionHelper {
|
||||
public:
|
||||
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
|
||||
virtual ~SimpleActionHelper();
|
||||
~SimpleActionHelper() override;
|
||||
void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
ReturnValue_t reportData(SerializeIF* data);
|
||||
|
||||
protected:
|
||||
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
store_address_t dataAddress);
|
||||
virtual void resetHelper();
|
||||
store_address_t dataAddress) override;
|
||||
void resetHelper() override;
|
||||
|
||||
private:
|
||||
bool isExecuting;
|
||||
@ -28,4 +28,4 @@ class SimpleActionHelper : public ActionHelper {
|
||||
uint8_t stepCount = 0;
|
||||
};
|
||||
|
||||
#endif /* SIMPLEACTIONHELPER_H_ */
|
||||
#endif /* FSFW_ACTION_SIMPLEACTIONHELPER_H_ */
|
||||
|
@ -26,7 +26,7 @@ ReturnValue_t ControllerBase::initialize() {
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
auto* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == nullptr) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
@ -52,7 +52,7 @@ MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->
|
||||
|
||||
void ControllerBase::handleQueue() {
|
||||
CommandMessage command;
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
ReturnValue_t result;
|
||||
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
|
||||
result = commandQueue->receiveMessage(&command)) {
|
||||
result = modeHelper.handleModeCommand(&command);
|
||||
@ -73,20 +73,20 @@ void ControllerBase::handleQueue() {
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) {
|
||||
changeHK(this->mode, this->submode, false);
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
this->mode = mode;
|
||||
this->submode = submode;
|
||||
mode = mode_;
|
||||
submode = submode_;
|
||||
modeHelper.modeChanged(mode, submode);
|
||||
modeChanged(mode, submode);
|
||||
announceMode(false);
|
||||
changeHK(this->mode, this->submode, true);
|
||||
}
|
||||
|
||||
void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) {
|
||||
*mode = this->mode;
|
||||
*submode = this->submode;
|
||||
void ControllerBase::getMode(Mode_t* mode_, Submode_t* submode_) {
|
||||
*mode_ = this->mode;
|
||||
*submode_ = this->submode;
|
||||
}
|
||||
|
||||
void ControllerBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
|
||||
@ -99,7 +99,7 @@ ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) { return; }
|
||||
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
|
||||
|
||||
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
||||
switch (health) {
|
||||
@ -115,6 +115,6 @@ ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
||||
HasHealthIF::HealthState ControllerBase::getHealth() { return healthHelper.getHealth(); }
|
||||
void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
||||
|
||||
void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {}
|
||||
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
|
||||
|
||||
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return HasReturnvaluesIF::RETURN_OK; }
|
||||
|
@ -24,21 +24,21 @@ class ControllerBase : public HasModesIF,
|
||||
static const Mode_t MODE_NORMAL = 2;
|
||||
|
||||
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
virtual ~ControllerBase();
|
||||
~ControllerBase() override;
|
||||
|
||||
/** SystemObject override */
|
||||
virtual ReturnValue_t initialize() override;
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const override;
|
||||
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
|
||||
|
||||
/** HasHealthIF overrides */
|
||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
||||
virtual HasHealthIF::HealthState getHealth() override;
|
||||
ReturnValue_t setHealth(HealthState health) override;
|
||||
HasHealthIF::HealthState getHealth() override;
|
||||
|
||||
/** ExecutableObjectIF overrides */
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
virtual void setTaskIF(PeriodicTaskIF *task) override;
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
void setTaskIF(PeriodicTaskIF *task) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -54,8 +54,8 @@ class ControllerBase : public HasModesIF,
|
||||
*/
|
||||
virtual void performControlOperation() = 0;
|
||||
|
||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override = 0;
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override = 0;
|
||||
|
||||
const object_id_t parentId;
|
||||
|
||||
@ -80,10 +80,10 @@ class ControllerBase : public HasModesIF,
|
||||
|
||||
/** Mode helpers */
|
||||
virtual void modeChanged(Mode_t mode, Submode_t submode);
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
virtual void setToExternalControl() override;
|
||||
virtual void announceMode(bool recursive);
|
||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
void setToExternalControl() override;
|
||||
void announceMode(bool recursive) override;
|
||||
/** HK helpers */
|
||||
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t
|
||||
poolManager(this, commandQueue),
|
||||
actionHelper(this, commandQueue) {}
|
||||
|
||||
ExtendedControllerBase::~ExtendedControllerBase() {}
|
||||
ExtendedControllerBase::~ExtendedControllerBase() = default;
|
||||
|
||||
ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
|
||||
MessageQueueId_t commandedBy,
|
||||
@ -31,7 +31,7 @@ ReturnValue_t ExtendedControllerBase::handleCommandMessage(CommandMessage *messa
|
||||
|
||||
void ExtendedControllerBase::handleQueue() {
|
||||
CommandMessage command;
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
ReturnValue_t result;
|
||||
for (result = commandQueue->receiveMessage(&command); result == RETURN_OK;
|
||||
result = commandQueue->receiveMessage(&command)) {
|
||||
result = actionHelper.handleActionMessage(&command);
|
||||
|
@ -18,16 +18,16 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
virtual ~ExtendedControllerBase();
|
||||
~ExtendedControllerBase() override;
|
||||
|
||||
/* SystemObjectIF overrides */
|
||||
virtual ReturnValue_t initialize() override;
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const override;
|
||||
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
|
||||
|
||||
/* ExecutableObjectIF overrides */
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
protected:
|
||||
LocalDataPoolManager poolManager;
|
||||
@ -39,32 +39,32 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t handleCommandMessage(CommandMessage* message) = 0;
|
||||
ReturnValue_t handleCommandMessage(CommandMessage* message) override = 0;
|
||||
|
||||
/**
|
||||
* Periodic helper from ControllerBase, implemented by child class.
|
||||
*/
|
||||
virtual void performControlOperation() = 0;
|
||||
void performControlOperation() override = 0;
|
||||
|
||||
/* Handle the four messages mentioned above */
|
||||
void handleQueue() override;
|
||||
|
||||
/* HasActionsIF overrides */
|
||||
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size) override;
|
||||
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size) override;
|
||||
|
||||
/* HasLocalDatapoolIF overrides */
|
||||
virtual LocalDataPoolManager* getHkManagerHandle() override;
|
||||
virtual object_id_t getObjectId() const override;
|
||||
virtual uint32_t getPeriodicOperationFrequency() const override;
|
||||
LocalDataPoolManager* getHkManagerHandle() override;
|
||||
[[nodiscard]] object_id_t getObjectId() const override;
|
||||
[[nodiscard]] uint32_t getPeriodicOperationFrequency() const override;
|
||||
|
||||
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) override = 0;
|
||||
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
|
||||
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) override = 0;
|
||||
LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override = 0;
|
||||
|
||||
// Mode abstract functions
|
||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t* msToReachTheMode) override = 0;
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t* msToReachTheMode) override = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ */
|
||||
|
@ -7,24 +7,26 @@
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValue, bool setValid)
|
||||
: length(static_cast<uint8_t>(initValue.size())), valid(setValid) {
|
||||
this->address = new T[this->length];
|
||||
if (initValue.size() == 0) {
|
||||
std::memset(this->address, 0, this->getByteSize());
|
||||
} else {
|
||||
std::copy(initValue.begin(), initValue.end(), this->address);
|
||||
PoolEntry<T>::PoolEntry(uint8_t len, bool setValid) : length(len), valid(setValid) {
|
||||
this->address = new T[this->length]();
|
||||
std::memset(this->address, 0, this->getByteSize());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValues, bool setValid)
|
||||
: length(static_cast<uint8_t>(initValues.size())), valid(setValid) {
|
||||
this->address = new T[this->length]();
|
||||
if (initValues.size() > 0) {
|
||||
std::copy(initValues.begin(), initValues.end(), this->address);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(T* initValue, uint8_t setLength, bool setValid)
|
||||
PoolEntry<T>::PoolEntry(const T* initValue, uint8_t setLength, bool setValid)
|
||||
: length(setLength), valid(setValid) {
|
||||
this->address = new T[this->length];
|
||||
this->address = new T[this->length]();
|
||||
if (initValue != nullptr) {
|
||||
std::memcpy(this->address, initValue, this->getByteSize());
|
||||
} else {
|
||||
std::memset(this->address, 0, this->getByteSize());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,9 @@ class PoolEntry : public PoolEntryIF {
|
||||
"instead! The ECSS standard defines a boolean as a one bit "
|
||||
"field. Therefore it is preferred to store a boolean as an "
|
||||
"uint8_t");
|
||||
|
||||
PoolEntry(uint8_t len = 1, bool setValid = false);
|
||||
|
||||
/**
|
||||
* @brief In the classe's constructor, space is allocated on the heap and
|
||||
* potential initialization values are copied to that space.
|
||||
@ -49,7 +52,7 @@ class PoolEntry : public PoolEntryIF {
|
||||
* @param setValid
|
||||
* Sets the initialization flag. It is invalid by default.
|
||||
*/
|
||||
PoolEntry(std::initializer_list<T> initValue = {0}, bool setValid = false);
|
||||
PoolEntry(std::initializer_list<T> initValue, bool setValid = false);
|
||||
|
||||
/**
|
||||
* @brief In the classe's constructor, space is allocated on the heap and
|
||||
@ -62,7 +65,7 @@ class PoolEntry : public PoolEntryIF {
|
||||
* @param setValid
|
||||
* Sets the initialization flag. It is invalid by default.
|
||||
*/
|
||||
PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false);
|
||||
PoolEntry(const T* initValue, uint8_t setLength = 1, bool setValid = false);
|
||||
|
||||
//! Explicitely deleted copy ctor, copying is not allowed.
|
||||
PoolEntry(const PoolEntry&) = delete;
|
||||
|
@ -696,7 +696,8 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
/* Configuration error */
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." << std::endl;
|
||||
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed."
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n");
|
||||
#endif
|
||||
|
@ -65,7 +65,9 @@ void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId
|
||||
}
|
||||
|
||||
DeviceHandlerBase::~DeviceHandlerBase() {
|
||||
delete comCookie;
|
||||
if (comCookie != nullptr) {
|
||||
delete comCookie;
|
||||
}
|
||||
if (defaultFDIRUsed) {
|
||||
delete fdirInstance;
|
||||
}
|
||||
@ -233,17 +235,26 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::decrementDeviceReplyMap() {
|
||||
bool timedOut = false;
|
||||
for (std::pair<const DeviceCommandId_t, DeviceReplyInfo>& replyPair : deviceReplyMap) {
|
||||
if (replyPair.second.delayCycles != 0) {
|
||||
if (replyPair.second.countdown != nullptr && replyPair.second.active) {
|
||||
if (replyPair.second.countdown->hasTimedOut()) {
|
||||
resetTimeoutControlledReply(&replyPair.second);
|
||||
timedOut = true;
|
||||
}
|
||||
}
|
||||
if (replyPair.second.delayCycles != 0 && replyPair.second.countdown == nullptr) {
|
||||
replyPair.second.delayCycles--;
|
||||
if (replyPair.second.delayCycles == 0) {
|
||||
if (replyPair.second.periodic) {
|
||||
replyPair.second.delayCycles = replyPair.second.maxDelayCycles;
|
||||
}
|
||||
replyToReply(replyPair.first, replyPair.second, TIMEOUT);
|
||||
missedReply(replyPair.first);
|
||||
resetDelayCyclesControlledReply(&replyPair.second);
|
||||
timedOut = true;
|
||||
}
|
||||
}
|
||||
if (timedOut) {
|
||||
replyToReply(replyPair.first, replyPair.second, TIMEOUT);
|
||||
missedReply(replyPair.first);
|
||||
timedOut = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -359,7 +370,6 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
setMode(MODE_OFF);
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(MODE_ERROR_ON);
|
||||
@ -408,20 +418,22 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
||||
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
|
||||
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) {
|
||||
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId,
|
||||
Countdown* countdown) {
|
||||
// No need to check, as we may try to insert multiple times.
|
||||
insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId);
|
||||
if (hasDifferentReplyId) {
|
||||
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic);
|
||||
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic, countdown);
|
||||
} else {
|
||||
return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic);
|
||||
return insertInReplyMap(deviceCommand, maxDelayCycles, replyDataSet, replyLen, periodic,
|
||||
countdown);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
||||
uint16_t maxDelayCycles,
|
||||
LocalPoolDataSetBase* dataSet, size_t replyLen,
|
||||
bool periodic) {
|
||||
bool periodic, Countdown* countdown) {
|
||||
DeviceReplyInfo info;
|
||||
info.maxDelayCycles = maxDelayCycles;
|
||||
info.periodic = periodic;
|
||||
@ -429,6 +441,7 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
||||
info.replyLen = replyLen;
|
||||
info.dataSet = dataSet;
|
||||
info.command = deviceCommandMap.end();
|
||||
info.countdown = countdown;
|
||||
auto resultPair = deviceReplyMap.emplace(replyId, info);
|
||||
if (resultPair.second) {
|
||||
return RETURN_OK;
|
||||
@ -464,7 +477,8 @@ size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
|
||||
}
|
||||
DeviceReplyIter iter = deviceReplyMap.find(replyId);
|
||||
if (iter != deviceReplyMap.end()) {
|
||||
if (iter->second.delayCycles != 0) {
|
||||
if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) ||
|
||||
(iter->second.active && iter->second.countdown != nullptr)) {
|
||||
return iter->second.replyLen;
|
||||
}
|
||||
}
|
||||
@ -500,9 +514,19 @@ ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandI
|
||||
return COMMAND_NOT_SUPPORTED;
|
||||
}
|
||||
if (enable) {
|
||||
info->delayCycles = info->maxDelayCycles;
|
||||
info->active = true;
|
||||
if (info->countdown != nullptr) {
|
||||
info->delayCycles = info->maxDelayCycles;
|
||||
} else {
|
||||
info->countdown->resetTimer();
|
||||
}
|
||||
} else {
|
||||
info->delayCycles = 0;
|
||||
info->active = false;
|
||||
if (info->countdown != nullptr) {
|
||||
info->delayCycles = 0;
|
||||
} else {
|
||||
info->countdown->timeOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
@ -808,17 +832,18 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
|
||||
|
||||
DeviceReplyInfo* info = &(iter->second);
|
||||
|
||||
if (info->delayCycles != 0) {
|
||||
if ((info->delayCycles != 0 && info->countdown == nullptr) ||
|
||||
(info->active && info->countdown != nullptr)) {
|
||||
result = interpretDeviceReply(foundId, receivedData);
|
||||
|
||||
if (result == IGNORE_REPLY_DATA) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->periodic) {
|
||||
info->delayCycles = info->maxDelayCycles;
|
||||
} else {
|
||||
info->delayCycles = 0;
|
||||
if (info->active && info->countdown != nullptr) {
|
||||
resetTimeoutControlledReply(info);
|
||||
} else if (info->delayCycles != 0) {
|
||||
resetDelayCyclesControlledReply(info);
|
||||
}
|
||||
|
||||
if (result != RETURN_OK) {
|
||||
@ -837,6 +862,24 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::resetTimeoutControlledReply(DeviceReplyInfo* info) {
|
||||
if (info->periodic) {
|
||||
info->countdown->resetTimer();
|
||||
} else {
|
||||
info->active = false;
|
||||
info->countdown->timeOut();
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::resetDelayCyclesControlledReply(DeviceReplyInfo* info) {
|
||||
if (info->periodic) {
|
||||
info->delayCycles = info->maxDelayCycles;
|
||||
} else {
|
||||
info->delayCycles = 0;
|
||||
info->active = false;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
|
||||
size_t* len) {
|
||||
size_t lenTmp;
|
||||
@ -959,9 +1002,15 @@ ReturnValue_t DeviceHandlerBase::enableReplyInReplyMap(DeviceCommandMap::iterato
|
||||
}
|
||||
if (iter != deviceReplyMap.end()) {
|
||||
DeviceReplyInfo* info = &(iter->second);
|
||||
// If a countdown has been set, the delay cycles will be ignored and the reply times out
|
||||
// as soon as the countdown has expired
|
||||
info->delayCycles = info->maxDelayCycles;
|
||||
info->command = command;
|
||||
command->second.expectedReplies = expectedReplies;
|
||||
if (info->countdown != nullptr) {
|
||||
info->countdown->resetTimer();
|
||||
}
|
||||
info->active = true;
|
||||
return RETURN_OK;
|
||||
} else {
|
||||
return NO_REPLY_EXPECTED;
|
||||
@ -1196,7 +1245,8 @@ void DeviceHandlerBase::setParentQueue(MessageQueueId_t parentQueueId) {
|
||||
bool DeviceHandlerBase::isAwaitingReply() {
|
||||
std::map<DeviceCommandId_t, DeviceReplyInfo>::iterator iter;
|
||||
for (iter = deviceReplyMap.begin(); iter != deviceReplyMap.end(); ++iter) {
|
||||
if (iter->second.delayCycles != 0) {
|
||||
if ((iter->second.delayCycles != 0 && iter->second.countdown == nullptr) ||
|
||||
(iter->second.active && iter->second.countdown != nullptr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1351,6 +1401,13 @@ uint8_t DeviceHandlerBase::getReplyDelayCycles(DeviceCommandId_t deviceCommand)
|
||||
DeviceReplyMap::iterator iter = deviceReplyMap.find(deviceCommand);
|
||||
if (iter == deviceReplyMap.end()) {
|
||||
return 0;
|
||||
} else if (iter->second.countdown != nullptr) {
|
||||
// fake a useful return value for legacy code
|
||||
if (iter->second.active) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return iter->second.delayCycles;
|
||||
}
|
||||
|
@ -448,6 +448,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||
* - @c RETURN_FAILED else.
|
||||
*/
|
||||
@ -455,7 +458,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
LocalPoolDataSetBase *replyDataSet = nullptr,
|
||||
size_t replyLen = 0, bool periodic = false,
|
||||
bool hasDifferentReplyId = false,
|
||||
DeviceCommandId_t replyId = 0);
|
||||
DeviceCommandId_t replyId = 0,
|
||||
Countdown *countdown = nullptr);
|
||||
/**
|
||||
* @brief This is a helper method to insert replies in the reply map.
|
||||
* @param deviceCommand Identifier of the reply to add.
|
||||
@ -465,12 +469,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||
* - @c RETURN_FAILED else.
|
||||
*/
|
||||
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
|
||||
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0,
|
||||
bool periodic = false);
|
||||
bool periodic = false, Countdown *countdown = nullptr);
|
||||
|
||||
/**
|
||||
* @brief A simple command to add a command to the commandList.
|
||||
@ -783,6 +790,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
LocalPoolDataSetBase *dataSet = nullptr;
|
||||
//! The command that expects this reply.
|
||||
DeviceCommandMap::iterator command;
|
||||
//! Instead of using delayCycles to specify the maximum time to wait for the device reply, it
|
||||
//! is also possible specify a countdown
|
||||
Countdown *countdown = nullptr;
|
||||
//! will be set to true when reply is enabled
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo>;
|
||||
@ -1244,6 +1256,17 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
void doGetRead(void);
|
||||
|
||||
/**
|
||||
* @brief Resets replies which use a timeout to detect missed replies.
|
||||
*/
|
||||
void resetTimeoutControlledReply(DeviceReplyInfo *info);
|
||||
|
||||
/**
|
||||
* @brief Resets replies which use a number of maximum delay cycles to detect
|
||||
* missed replies.
|
||||
*/
|
||||
void resetDelayCyclesControlledReply(DeviceReplyInfo *info);
|
||||
|
||||
/**
|
||||
* Retrive data from the #IPCStore.
|
||||
*
|
||||
|
@ -88,6 +88,11 @@ ReturnValue_t EventManager::subscribeToEventRange(MessageQueueId_t listener, Eve
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t EventManager::unsubscribeFromAllEvents(MessageQueueId_t listener,
|
||||
object_id_t object) {
|
||||
return unsubscribeFromEventRange(listener, 0, 0, true, object);
|
||||
}
|
||||
|
||||
ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom,
|
||||
EventId_t idTo, bool idInverted,
|
||||
object_id_t reporterFrom,
|
||||
|
@ -37,6 +37,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
|
||||
EventId_t idTo = 0, bool idInverted = false,
|
||||
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
||||
bool reporterInverted = false);
|
||||
ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object);
|
||||
ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||
EventId_t idTo = 0, bool idInverted = false,
|
||||
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
||||
|
@ -20,6 +20,7 @@ class EventManagerIF {
|
||||
bool forwardAllButSelected = false) = 0;
|
||||
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
|
||||
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
|
||||
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;
|
||||
virtual ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||
EventId_t idTo = 0, bool idInverted = false,
|
||||
object_id_t reporterFrom = 0,
|
||||
|
@ -14,6 +14,16 @@ FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent
|
||||
}
|
||||
|
||||
FailureIsolationBase::~FailureIsolationBase() {
|
||||
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
|
||||
if (manager == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FailureIsolationBase::~FailureIsolationBase: Event Manager has not"
|
||||
" been initialized!"
|
||||
<< std::endl;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
|
||||
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
||||
}
|
||||
|
||||
|
@ -60,14 +60,14 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
return INVALID_DOMAIN_ID;
|
||||
}
|
||||
|
||||
switch (uniqueId) {
|
||||
case 0:
|
||||
switch (static_cast<ParameterIds>(uniqueId)) {
|
||||
case ParameterIds::FAILURE_THRESHOLD:
|
||||
parameterWrapper->set(failureThreshold);
|
||||
break;
|
||||
case 1:
|
||||
case ParameterIds::FAULT_COUNT:
|
||||
parameterWrapper->set(faultCount);
|
||||
break;
|
||||
case 2:
|
||||
case ParameterIds::TIMEOUT:
|
||||
parameterWrapper->set(timer.timeout);
|
||||
break;
|
||||
default:
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
class FaultCounter : public HasParametersIF {
|
||||
public:
|
||||
enum class ParameterIds { FAILURE_THRESHOLD, FAULT_COUNT, TIMEOUT };
|
||||
|
||||
FaultCounter();
|
||||
FaultCounter(uint32_t failureThreshold, uint32_t decrementAfterMs,
|
||||
uint8_t setParameterDomain = 0);
|
||||
@ -25,7 +27,8 @@ class FaultCounter : public HasParametersIF {
|
||||
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
const ParameterWrapper *newValues, uint16_t startAtIndex);
|
||||
const ParameterWrapper *newValues = nullptr,
|
||||
uint16_t startAtIndex = 0);
|
||||
|
||||
void setParameterDomain(uint8_t domain);
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId)
|
||||
: objectId(objectId), owner(owner) {}
|
||||
|
||||
HealthHelper::~HealthHelper() {}
|
||||
HealthHelper::~HealthHelper() { healthTable->removeObject(objectId); }
|
||||
|
||||
ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) {
|
||||
switch (message->getCommand()) {
|
||||
|
@ -27,6 +27,15 @@ ReturnValue_t HealthTable::registerObject(object_id_t object,
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t HealthTable::removeObject(object_id_t object) {
|
||||
mapIterator = healthMap.find(object);
|
||||
if (mapIterator == healthMap.end()) {
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
healthMap.erase(mapIterator);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void HealthTable::setHealth(object_id_t object, HasHealthIF::HealthState newState) {
|
||||
MutexGuard(mutex, timeoutType, mutexTimeoutMs);
|
||||
HealthMap::iterator iter = healthMap.find(object);
|
||||
|
@ -17,6 +17,7 @@ class HealthTable : public HealthTableIF, public SystemObject {
|
||||
/** HealthTableIF overrides */
|
||||
virtual ReturnValue_t registerObject(
|
||||
object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) override;
|
||||
ReturnValue_t removeObject(object_id_t object) override;
|
||||
virtual size_t getPrintSize() override;
|
||||
virtual void printAll(uint8_t* pointer, size_t maxSize) override;
|
||||
|
||||
|
@ -14,6 +14,8 @@ class HealthTableIF : public ManagesHealthIF {
|
||||
virtual ReturnValue_t registerObject(
|
||||
object_id_t object, HasHealthIF::HealthState initilialState = HasHealthIF::HEALTHY) = 0;
|
||||
|
||||
virtual ReturnValue_t removeObject(object_id_t objectId) = 0;
|
||||
|
||||
virtual size_t getPrintSize() = 0;
|
||||
virtual void printAll(uint8_t *pointer, size_t maxSize) = 0;
|
||||
|
||||
|
@ -54,7 +54,7 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
||||
// If the deadline was missed, the deadlineMissedFunc is called.
|
||||
if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
|
||||
// No time left on timer -> we missed the deadline
|
||||
if(dlmFunc != nullptr){
|
||||
if (dlmFunc != nullptr) {
|
||||
dlmFunc();
|
||||
}
|
||||
}
|
||||
|
@ -290,10 +290,9 @@ ReturnValue_t MessageQueue::handleOpenError(mq_attr* attributes, uint32_t messag
|
||||
*/
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MessageQueue::MessageQueue: Default MQ size " << defaultMqMaxMsg
|
||||
<< " is too small for requested size " << messageDepth << std::endl;
|
||||
<< " is too small for requested message depth " << messageDepth << std::endl;
|
||||
sif::error << "This error can be fixed by setting the maximum "
|
||||
"allowed message size higher!"
|
||||
<< std::endl;
|
||||
"allowed message depth higher" << std::endl;
|
||||
#else
|
||||
sif::printError(
|
||||
"MessageQueue::MessageQueue: Default MQ size %d is too small for"
|
||||
|
@ -26,3 +26,4 @@ add_subdirectory(tmtcpacket)
|
||||
add_subdirectory(cfdp)
|
||||
add_subdirectory(hal)
|
||||
add_subdirectory(internalerror)
|
||||
add_subdirectory(devicehandler)
|
||||
|
@ -65,7 +65,7 @@ void Factory::setStaticFrameworkObjectIds() {
|
||||
VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION;
|
||||
|
||||
DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
||||
DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS;
|
||||
DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT;
|
||||
|
||||
LocalDataPoolManager::defaultHkDestination = objects::HK_RECEIVER_MOCK;
|
||||
|
||||
|
8
tests/src/fsfw_tests/unit/devicehandler/CMakeLists.txt
Normal file
8
tests/src/fsfw_tests/unit/devicehandler/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE
|
||||
CookieIFMock.cpp
|
||||
ComIFMock.cpp
|
||||
DeviceHandlerCommander.cpp
|
||||
DeviceHandlerMock.cpp
|
||||
DeviceFdirMock.cpp
|
||||
TestDeviceHandlerBase.cpp
|
||||
)
|
46
tests/src/fsfw_tests/unit/devicehandler/ComIFMock.cpp
Normal file
46
tests/src/fsfw_tests/unit/devicehandler/ComIFMock.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "ComIFMock.h"
|
||||
|
||||
#include "DeviceHandlerMock.h"
|
||||
|
||||
ComIFMock::ComIFMock(object_id_t objectId) : SystemObject(objectId) {}
|
||||
|
||||
ComIFMock::~ComIFMock() {}
|
||||
|
||||
ReturnValue_t ComIFMock::initializeInterface(CookieIF *cookie) { return RETURN_OK; }
|
||||
|
||||
ReturnValue_t ComIFMock::sendMessage(CookieIF *cookie, const uint8_t *sendData, size_t sendLen) {
|
||||
data = *sendData;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t ComIFMock::getSendSuccess(CookieIF *cookie) { return RETURN_OK; }
|
||||
|
||||
ReturnValue_t ComIFMock::requestReceiveMessage(CookieIF *cookie, size_t requestLen) {
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t ComIFMock::readReceivedMessage(CookieIF *cookie, uint8_t **buffer, size_t *size) {
|
||||
switch (testCase) {
|
||||
case TestCase::MISSED_REPLY: {
|
||||
*size = 0;
|
||||
return RETURN_OK;
|
||||
}
|
||||
case TestCase::SIMPLE_COMMAND_NOMINAL: {
|
||||
*size = 1;
|
||||
data = DeviceHandlerMock::SIMPLE_COMMAND_DATA;
|
||||
*buffer = &data;
|
||||
break;
|
||||
}
|
||||
case TestCase::PERIODIC_REPLY_NOMINAL: {
|
||||
*size = 1;
|
||||
data = DeviceHandlerMock::PERIODIC_REPLY_DATA;
|
||||
*buffer = &data;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void ComIFMock::setTestCase(TestCase testCase_) { testCase = testCase_; }
|
37
tests/src/fsfw_tests/unit/devicehandler/ComIFMock.h
Normal file
37
tests/src/fsfw_tests/unit/devicehandler/ComIFMock.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COMIFMOCK_H_
|
||||
#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COMIFMOCK_H_
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
|
||||
/**
|
||||
* @brief The ComIFMock supports the simulation of various device communication error cases
|
||||
* like incomplete or wrong replies and can be used to test the
|
||||
* DeviceHandlerBase.
|
||||
*/
|
||||
class ComIFMock : public DeviceCommunicationIF, public SystemObject {
|
||||
public:
|
||||
enum class TestCase { SIMPLE_COMMAND_NOMINAL, PERIODIC_REPLY_NOMINAL, MISSED_REPLY };
|
||||
|
||||
ComIFMock(object_id_t objectId);
|
||||
virtual ~ComIFMock();
|
||||
|
||||
virtual ReturnValue_t initializeInterface(CookieIF *cookie) override;
|
||||
virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t *sendData,
|
||||
size_t sendLen) override;
|
||||
virtual ReturnValue_t getSendSuccess(CookieIF *cookie) override;
|
||||
virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen) override;
|
||||
virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer,
|
||||
size_t *size) override;
|
||||
void setTestCase(TestCase testCase_);
|
||||
|
||||
private:
|
||||
TestCase testCase = TestCase::SIMPLE_COMMAND_NOMINAL;
|
||||
|
||||
static const uint8_t SIMPLE_COMMAND_DATA = 1;
|
||||
static const uint8_t PERIODIC_REPLY_DATA = 2;
|
||||
|
||||
uint8_t data = 0;
|
||||
};
|
||||
|
||||
#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COMIFMOCK_H_ */
|
5
tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.cpp
Normal file
5
tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "CookieIFMock.h"
|
||||
|
||||
CookieIFMock::CookieIFMock() {}
|
||||
|
||||
CookieIFMock::~CookieIFMock() {}
|
12
tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.h
Normal file
12
tests/src/fsfw_tests/unit/devicehandler/CookieIFMock.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COOKIEIFMOCK_H_
|
||||
#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COOKIEIFMOCK_H_
|
||||
|
||||
#include "fsfw/devicehandlers/CookieIF.h"
|
||||
|
||||
class CookieIFMock : public CookieIF {
|
||||
public:
|
||||
CookieIFMock();
|
||||
virtual ~CookieIFMock();
|
||||
};
|
||||
|
||||
#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_COOKIEIFMOCK_H_ */
|
18
tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.cpp
Normal file
18
tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "DeviceFdirMock.h"
|
||||
|
||||
#include <tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.h>
|
||||
|
||||
DeviceFdirMock::DeviceFdirMock(object_id_t owner, object_id_t parent)
|
||||
: DeviceHandlerFailureIsolation(owner, parent) {}
|
||||
|
||||
DeviceFdirMock::~DeviceFdirMock() {}
|
||||
|
||||
uint32_t DeviceFdirMock::getMissedReplyCount() {
|
||||
ParameterWrapper parameterWrapper;
|
||||
this->getParameter(MISSED_REPLY_DOMAIN_ID,
|
||||
static_cast<uint8_t>(FaultCounter::ParameterIds::FAULT_COUNT),
|
||||
¶meterWrapper, nullptr, 0);
|
||||
uint32_t missedReplyCount = 0;
|
||||
parameterWrapper.getElement(&missedReplyCount);
|
||||
return missedReplyCount;
|
||||
}
|
18
tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.h
Normal file
18
tests/src/fsfw_tests/unit/devicehandler/DeviceFdirMock.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEFDIRMOCK_H_
|
||||
#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEFDIRMOCK_H_
|
||||
|
||||
#include "fsfw/devicehandlers/DeviceHandlerFailureIsolation.h"
|
||||
|
||||
class DeviceFdirMock : public DeviceHandlerFailureIsolation {
|
||||
public:
|
||||
DeviceFdirMock(object_id_t owner, object_id_t parent);
|
||||
virtual ~DeviceFdirMock();
|
||||
|
||||
uint32_t getMissedReplyCount();
|
||||
|
||||
private:
|
||||
static const uint8_t STRANGE_REPLY_DOMAIN_ID = 0xF0;
|
||||
static const uint8_t MISSED_REPLY_DOMAIN_ID = 0xF1;
|
||||
};
|
||||
|
||||
#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEFDIRMOCK_H_ */
|
@ -0,0 +1,64 @@
|
||||
#include "DeviceHandlerCommander.h"
|
||||
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
|
||||
DeviceHandlerCommander::DeviceHandlerCommander(object_id_t objectId)
|
||||
: SystemObject(objectId), commandActionHelper(this) {
|
||||
auto mqArgs = MqArgs(this->getObjectId());
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
DeviceHandlerCommander::~DeviceHandlerCommander() {}
|
||||
|
||||
ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) {
|
||||
readCommandQueue();
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerCommander::initialize() {
|
||||
ReturnValue_t result = commandActionHelper.initialize();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
MessageQueueIF* DeviceHandlerCommander::getCommandQueuePtr() { return commandQueue; }
|
||||
|
||||
void DeviceHandlerCommander::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {}
|
||||
|
||||
void DeviceHandlerCommander::stepFailedReceived(ActionId_t actionId, uint8_t step,
|
||||
ReturnValue_t returnCode) {}
|
||||
|
||||
void DeviceHandlerCommander::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) {
|
||||
}
|
||||
|
||||
void DeviceHandlerCommander::completionSuccessfulReceived(ActionId_t actionId) {
|
||||
lastReplyReturnCode = RETURN_OK;
|
||||
}
|
||||
|
||||
void DeviceHandlerCommander::completionFailedReceived(ActionId_t actionId,
|
||||
ReturnValue_t returnCode) {
|
||||
lastReplyReturnCode = returnCode;
|
||||
}
|
||||
|
||||
void DeviceHandlerCommander::readCommandQueue() {
|
||||
CommandMessage message;
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||
for (result = commandQueue->receiveMessage(&message); result == HasReturnvaluesIF::RETURN_OK;
|
||||
result = commandQueue->receiveMessage(&message)) {
|
||||
result = commandActionHelper.handleReply(&message);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerCommander::sendCommand(object_id_t target, ActionId_t actionId) {
|
||||
return commandActionHelper.commandAction(target, actionId, nullptr, 0);
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerCommander::getReplyReturnCode() { return lastReplyReturnCode; }
|
||||
|
||||
void DeviceHandlerCommander::resetReplyReturnCode() { lastReplyReturnCode = RETURN_FAILED; }
|
@ -0,0 +1,50 @@
|
||||
#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERCOMMANDER_H_
|
||||
#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERCOMMANDER_H_
|
||||
|
||||
#include "fsfw/action/CommandActionHelper.h"
|
||||
#include "fsfw/action/CommandsActionsIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
|
||||
class DeviceHandlerCommander : public ExecutableObjectIF,
|
||||
public SystemObject,
|
||||
public CommandsActionsIF,
|
||||
public HasReturnvaluesIF {
|
||||
public:
|
||||
DeviceHandlerCommander(object_id_t objectId);
|
||||
virtual ~DeviceHandlerCommander();
|
||||
|
||||
ReturnValue_t performOperation(uint8_t operationCode = 0);
|
||||
ReturnValue_t initialize() override;
|
||||
MessageQueueIF* getCommandQueuePtr() override;
|
||||
void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) override;
|
||||
void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) override;
|
||||
void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) override;
|
||||
void completionSuccessfulReceived(ActionId_t actionId) override;
|
||||
void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) override;
|
||||
|
||||
/**
|
||||
* @brief Calling this function will send the command to the device handler object.
|
||||
*
|
||||
* @param target Object ID of the device handler
|
||||
* @param actionId Action ID of the command to send
|
||||
*/
|
||||
ReturnValue_t sendCommand(object_id_t target, ActionId_t actionId);
|
||||
|
||||
ReturnValue_t getReplyReturnCode();
|
||||
void resetReplyReturnCode();
|
||||
|
||||
private:
|
||||
static const uint32_t QUEUE_SIZE = 20;
|
||||
|
||||
MessageQueueIF* commandQueue = nullptr;
|
||||
|
||||
CommandActionHelper commandActionHelper;
|
||||
|
||||
ReturnValue_t lastReplyReturnCode = RETURN_FAILED;
|
||||
|
||||
void readCommandQueue();
|
||||
};
|
||||
|
||||
#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERCOMMANDER_H_ */
|
103
tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.cpp
Normal file
103
tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "DeviceHandlerMock.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
DeviceHandlerMock::DeviceHandlerMock(object_id_t objectId, object_id_t deviceCommunication,
|
||||
CookieIF *comCookie, FailureIsolationBase *fdirInstance)
|
||||
: DeviceHandlerBase(objectId, deviceCommunication, comCookie, fdirInstance) {
|
||||
mode = MODE_ON;
|
||||
}
|
||||
|
||||
DeviceHandlerMock::~DeviceHandlerMock() {}
|
||||
|
||||
void DeviceHandlerMock::doStartUp() { setMode(_MODE_TO_ON); }
|
||||
|
||||
void DeviceHandlerMock::doShutDown() { setMode(_MODE_POWER_DOWN); }
|
||||
|
||||
ReturnValue_t DeviceHandlerMock::buildNormalDeviceCommand(DeviceCommandId_t *id) {
|
||||
return NOTHING_TO_SEND;
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerMock::buildTransitionDeviceCommand(DeviceCommandId_t *id) {
|
||||
return NOTHING_TO_SEND;
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerMock::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
|
||||
const uint8_t *commandData,
|
||||
size_t commandDataLen) {
|
||||
switch (deviceCommand) {
|
||||
case SIMPLE_COMMAND: {
|
||||
commandBuffer[0] = SIMPLE_COMMAND_DATA;
|
||||
rawPacket = commandBuffer;
|
||||
rawPacketLen = sizeof(SIMPLE_COMMAND_DATA);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN("DeviceHandlerMock::buildCommandFromCommand: Invalid device command");
|
||||
break;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerMock::scanForReply(const uint8_t *start, size_t len,
|
||||
DeviceCommandId_t *foundId, size_t *foundLen) {
|
||||
switch (*start) {
|
||||
case SIMPLE_COMMAND_DATA: {
|
||||
*foundId = SIMPLE_COMMAND;
|
||||
*foundLen = sizeof(SIMPLE_COMMAND_DATA);
|
||||
return RETURN_OK;
|
||||
break;
|
||||
}
|
||||
case PERIODIC_REPLY_DATA: {
|
||||
*foundId = PERIODIC_REPLY;
|
||||
*foundLen = sizeof(PERIODIC_REPLY_DATA);
|
||||
return RETURN_OK;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerMock::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) {
|
||||
switch (id) {
|
||||
case SIMPLE_COMMAND:
|
||||
case PERIODIC_REPLY: {
|
||||
periodicReplyReceived = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void DeviceHandlerMock::fillCommandAndReplyMap() {
|
||||
insertInCommandAndReplyMap(SIMPLE_COMMAND, 0, nullptr, 0, false, false, 0,
|
||||
&simpleCommandReplyTimeout);
|
||||
insertInCommandAndReplyMap(PERIODIC_REPLY, 0, nullptr, 0, true, false, 0,
|
||||
&periodicReplyCountdown);
|
||||
}
|
||||
|
||||
uint32_t DeviceHandlerMock::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return 500; }
|
||||
|
||||
void DeviceHandlerMock::changePeriodicReplyCountdown(uint32_t timeout) {
|
||||
periodicReplyCountdown.setTimeout(timeout);
|
||||
}
|
||||
|
||||
void DeviceHandlerMock::changeSimpleCommandReplyCountdown(uint32_t timeout) {
|
||||
simpleCommandReplyTimeout.setTimeout(timeout);
|
||||
}
|
||||
|
||||
void DeviceHandlerMock::resetPeriodicReplyState() { periodicReplyReceived = false; }
|
||||
|
||||
bool DeviceHandlerMock::getPeriodicReplyReceived() { return periodicReplyReceived; }
|
||||
|
||||
ReturnValue_t DeviceHandlerMock::enablePeriodicReply(DeviceCommandId_t replyId) {
|
||||
return updatePeriodicReply(true, replyId);
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerMock::disablePeriodicReply(DeviceCommandId_t replyId) {
|
||||
return updatePeriodicReply(false, replyId);
|
||||
}
|
46
tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.h
Normal file
46
tests/src/fsfw_tests/unit/devicehandler/DeviceHandlerMock.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERMOCK_H_
|
||||
#define TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERMOCK_H_
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
|
||||
|
||||
class DeviceHandlerMock : public DeviceHandlerBase {
|
||||
public:
|
||||
static const DeviceCommandId_t SIMPLE_COMMAND = 1;
|
||||
static const DeviceCommandId_t PERIODIC_REPLY = 2;
|
||||
|
||||
static const uint8_t SIMPLE_COMMAND_DATA = 1;
|
||||
static const uint8_t PERIODIC_REPLY_DATA = 2;
|
||||
|
||||
DeviceHandlerMock(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||
FailureIsolationBase *fdirInstance);
|
||||
virtual ~DeviceHandlerMock();
|
||||
void changePeriodicReplyCountdown(uint32_t timeout);
|
||||
void changeSimpleCommandReplyCountdown(uint32_t timeout);
|
||||
void resetPeriodicReplyState();
|
||||
bool getPeriodicReplyReceived();
|
||||
ReturnValue_t enablePeriodicReply(DeviceCommandId_t replyId);
|
||||
ReturnValue_t disablePeriodicReply(DeviceCommandId_t replyId);
|
||||
|
||||
protected:
|
||||
void doStartUp() override;
|
||||
void doShutDown() override;
|
||||
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
|
||||
ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t *id) override;
|
||||
ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t *commandData,
|
||||
size_t commandDataLen) override;
|
||||
ReturnValue_t scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId,
|
||||
size_t *foundLen) override;
|
||||
ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override;
|
||||
void fillCommandAndReplyMap() override;
|
||||
uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
|
||||
|
||||
private:
|
||||
Countdown simpleCommandReplyTimeout = Countdown(1000);
|
||||
Countdown periodicReplyCountdown = Countdown(1000);
|
||||
|
||||
uint8_t commandBuffer[1];
|
||||
|
||||
bool periodicReplyReceived = false;
|
||||
};
|
||||
|
||||
#endif /* TESTS_SRC_FSFW_TESTS_UNIT_DEVICEHANDLER_DEVICEHANDLERMOCK_H_ */
|
@ -0,0 +1,95 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "ComIFMock.h"
|
||||
#include "DeviceFdirMock.h"
|
||||
#include "fsfw_tests/unit/devicehandler/CookieIFMock.h"
|
||||
#include "fsfw_tests/unit/devicehandler/DeviceHandlerCommander.h"
|
||||
#include "fsfw_tests/unit/devicehandler/DeviceHandlerMock.h"
|
||||
#include "fsfw_tests/unit/testcfg/objects/systemObjectList.h"
|
||||
|
||||
TEST_CASE("Device Handler Base", "[DeviceHandlerBase]") {
|
||||
// Will be deleted with DHB destructor
|
||||
CookieIFMock* cookieIFMock = new CookieIFMock;
|
||||
ComIFMock comIF(objects::COM_IF_MOCK);
|
||||
DeviceFdirMock deviceFdirMock(objects::DEVICE_HANDLER_MOCK, objects::NO_OBJECT);
|
||||
DeviceHandlerMock deviceHandlerMock(objects::DEVICE_HANDLER_MOCK, objects::COM_IF_MOCK,
|
||||
cookieIFMock, &deviceFdirMock);
|
||||
ReturnValue_t result = deviceHandlerMock.initialize();
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
DeviceHandlerCommander deviceHandlerCommander(objects::DEVICE_HANDLER_COMMANDER);
|
||||
result = deviceHandlerCommander.initialize();
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
|
||||
SECTION("Commanding nominal") {
|
||||
comIF.setTestCase(ComIFMock::TestCase::SIMPLE_COMMAND_NOMINAL);
|
||||
result = deviceHandlerCommander.sendCommand(objects::DEVICE_HANDLER_MOCK,
|
||||
DeviceHandlerMock::SIMPLE_COMMAND);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ);
|
||||
deviceHandlerCommander.performOperation();
|
||||
result = deviceHandlerCommander.getReplyReturnCode();
|
||||
uint32_t missedReplies = deviceFdirMock.getMissedReplyCount();
|
||||
REQUIRE(missedReplies == 0);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
}
|
||||
|
||||
SECTION("Commanding missed reply") {
|
||||
comIF.setTestCase(ComIFMock::TestCase::MISSED_REPLY);
|
||||
deviceHandlerCommander.resetReplyReturnCode();
|
||||
// Set the timeout to 0 to immediately timeout the reply
|
||||
deviceHandlerMock.changeSimpleCommandReplyCountdown(0);
|
||||
result = deviceHandlerCommander.sendCommand(objects::DEVICE_HANDLER_MOCK,
|
||||
DeviceHandlerMock::SIMPLE_COMMAND);
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION);
|
||||
deviceHandlerCommander.performOperation();
|
||||
result = deviceHandlerCommander.getReplyReturnCode();
|
||||
REQUIRE(result == DeviceHandlerIF::TIMEOUT);
|
||||
uint32_t missedReplies = deviceFdirMock.getMissedReplyCount();
|
||||
REQUIRE(missedReplies == 1);
|
||||
}
|
||||
|
||||
SECTION("Periodic reply nominal") {
|
||||
comIF.setTestCase(ComIFMock::TestCase::PERIODIC_REPLY_NOMINAL);
|
||||
deviceHandlerMock.enablePeriodicReply(DeviceHandlerMock::PERIODIC_REPLY);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ);
|
||||
REQUIRE(deviceHandlerMock.getPeriodicReplyReceived() == true);
|
||||
}
|
||||
|
||||
SECTION("Missed periodic reply") {
|
||||
comIF.setTestCase(ComIFMock::TestCase::MISSED_REPLY);
|
||||
// Set the timeout to 0 to immediately timeout the reply
|
||||
deviceHandlerMock.changePeriodicReplyCountdown(0);
|
||||
deviceHandlerMock.enablePeriodicReply(DeviceHandlerMock::PERIODIC_REPLY);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ);
|
||||
uint32_t missedReplies = deviceFdirMock.getMissedReplyCount();
|
||||
REQUIRE(missedReplies == 1);
|
||||
// Test if disabling of periodic reply
|
||||
deviceHandlerMock.disablePeriodicReply(DeviceHandlerMock::PERIODIC_REPLY);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::PERFORM_OPERATION);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_WRITE);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::SEND_READ);
|
||||
deviceHandlerMock.performOperation(DeviceHandlerIF::GET_READ);
|
||||
missedReplies = deviceFdirMock.getMissedReplyCount();
|
||||
// Should still be 1 because periodic reply is now disabled
|
||||
REQUIRE(missedReplies == 1);
|
||||
}
|
||||
}
|
@ -4,12 +4,12 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "tests/TestsConfig.h"
|
||||
#include "fsfw/container/DynamicFIFO.h"
|
||||
#include "fsfw/container/SimpleRingBuffer.h"
|
||||
#include "fsfw/platform.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw_hal/linux/CommandExecutor.h"
|
||||
#include "tests/TestsConfig.h"
|
||||
|
||||
#ifdef PLATFORM_UNIX
|
||||
|
||||
|
@ -157,7 +157,7 @@ TEST_CASE("New Accessor", "[NewAccessor]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Operators"){
|
||||
SECTION("Operators") {
|
||||
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
{
|
||||
@ -173,13 +173,13 @@ TEST_CASE("New Accessor", "[NewAccessor]") {
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
|
||||
CHECK(accessor2.getId() == testStoreId);
|
||||
CHECK(accessor2.size() == 10);
|
||||
|
||||
|
||||
std::array<uint8_t, 10> newData;
|
||||
// Expect data to be invalid so this must return RETURN_FAILED
|
||||
result = accessor.getDataCopy(newData.data(),newData.size());
|
||||
result = accessor.getDataCopy(newData.data(), newData.size());
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
|
||||
// Expect data to be too small
|
||||
result = accessor2.getDataCopy(data.data(),data.size());
|
||||
// Expect data to be too small
|
||||
result = accessor2.getDataCopy(data.data(), data.size());
|
||||
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/storagemanager/LocalPool.h>
|
||||
|
||||
#include <array>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
|
||||
#include "fsfw_tests/unit/CatchDefinitions.h"
|
||||
|
||||
|
@ -1,30 +1,34 @@
|
||||
#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "fsfw/objectmanager/frameworkObjects.h"
|
||||
|
||||
// The objects will be instantiated in the ID order
|
||||
namespace objects {
|
||||
enum sourceObjects : uint32_t {
|
||||
/* All addresses between start and end are reserved for the FSFW */
|
||||
FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION,
|
||||
FSFW_CONFIG_RESERVED_END = TM_STORE,
|
||||
|
||||
UDP_BRIDGE = 15,
|
||||
UDP_POLLING_TASK = 16,
|
||||
|
||||
TEST_ECHO_COM_IF = 20,
|
||||
TEST_DEVICE = 21,
|
||||
|
||||
HK_RECEIVER_MOCK = 22,
|
||||
TEST_LOCAL_POOL_OWNER_BASE = 25,
|
||||
|
||||
SHARED_SET_ID = 26,
|
||||
|
||||
DUMMY_POWER_SWITCHER = 27
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */
|
||||
#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "fsfw/objectmanager/frameworkObjects.h"
|
||||
|
||||
// The objects will be instantiated in the ID order
|
||||
namespace objects {
|
||||
enum sourceObjects : uint32_t {
|
||||
/* All addresses between start and end are reserved for the FSFW */
|
||||
FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION,
|
||||
FSFW_CONFIG_RESERVED_END = TM_STORE,
|
||||
|
||||
UDP_BRIDGE = 15,
|
||||
UDP_POLLING_TASK = 16,
|
||||
|
||||
TEST_ECHO_COM_IF = 20,
|
||||
TEST_DEVICE = 21,
|
||||
|
||||
HK_RECEIVER_MOCK = 22,
|
||||
TEST_LOCAL_POOL_OWNER_BASE = 25,
|
||||
|
||||
SHARED_SET_ID = 26,
|
||||
|
||||
DUMMY_POWER_SWITCHER = 28,
|
||||
|
||||
DEVICE_HANDLER_MOCK = 29,
|
||||
COM_IF_MOCK = 30,
|
||||
DEVICE_HANDLER_COMMANDER = 40,
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user