-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial commit for Svc::CmdSplitter #2081
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
set(SOURCE_FILES | ||
"${CMAKE_CURRENT_LIST_DIR}/CmdSplitter.fpp" | ||
"${CMAKE_CURRENT_LIST_DIR}/CmdSplitter.cpp" | ||
) | ||
register_fprime_module() | ||
|
||
set(UT_SOURCE_FILES | ||
"${CMAKE_CURRENT_LIST_DIR}/CmdSplitter.fpp" | ||
"${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" | ||
"${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" | ||
|
||
) | ||
set(UT_MOD_DEPS STest) | ||
set(UT_AUTO_HELPERS ON) | ||
register_fprime_ut() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// ====================================================================== | ||
// \title CmdSplitter.cpp | ||
// \author watney | ||
// \brief cpp file for CmdSplitter component implementation class | ||
// ====================================================================== | ||
|
||
#include <FpConfig.hpp> | ||
#include <Fw/Cmd/CmdPacket.hpp> | ||
#include <Svc/CmdSplitter/CmdSplitter.hpp> | ||
#include <config/CmdSplitterCfg.hpp> | ||
|
||
namespace Svc { | ||
|
||
// ---------------------------------------------------------------------- | ||
// Construction, initialization, and destruction | ||
// ---------------------------------------------------------------------- | ||
|
||
CmdSplitter ::CmdSplitter(const char* const compName) : CmdSplitterComponentBase(compName) {} | ||
Check notice Code scanning / CodeQL Use of basic integral type Note
compName uses the basic integral type char rather than a typedef with size and signedness.
|
||
|
||
CmdSplitter ::~CmdSplitter() {} | ||
Check notice Code scanning / CodeQL More than one statement per line Note
This line contains 2 statements; only one is allowed.
|
||
|
||
// ---------------------------------------------------------------------- | ||
// Handler implementations for user-defined typed input ports | ||
// ---------------------------------------------------------------------- | ||
|
||
void CmdSplitter ::CmdBuff_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { | ||
Check notice Code scanning / CodeQL Long function without assertion Note
All functions of more than 10 lines should have at least one assertion.
Check notice Code scanning / CodeQL Use of basic integral type Note
portNum uses the basic integral type int rather than a typedef with size and signedness.
|
||
Fw::CmdPacket cmdPkt; | ||
Fw::SerializeStatus stat = cmdPkt.deserialize(data); | ||
Check warning Code scanning / CodeQL Unchecked function argument Warning
This use of parameter data has not been checked.
|
||
|
||
if (stat != Fw::FW_SERIALIZE_OK) { | ||
// Let the local command dispatcher deal with it | ||
this->LocalCmd_out(0, data, context); | ||
Check warning Code scanning / CodeQL Unchecked function argument Warning
This use of parameter context has not been checked.
|
||
} else { | ||
// Check if local or remote | ||
if (cmdPkt.getOpCode() < CMD_SPLITTER_REMOTE_OPCODE_BASE) { | ||
this->LocalCmd_out(0, data, context); | ||
Check warning Code scanning / CodeQL Unchecked function argument Warning
This use of parameter context has not been checked.
|
||
} else { | ||
this->RemoteCmd_out(0, data, context); | ||
Check warning Code scanning / CodeQL Unchecked function argument Warning
This use of parameter context has not been checked.
|
||
} | ||
} | ||
} | ||
|
||
void CmdSplitter ::seqCmdStatus_handler(const NATIVE_INT_TYPE portNum, | ||
Check notice Code scanning / CodeQL Use of basic integral type Note
portNum uses the basic integral type int rather than a typedef with size and signedness.
|
||
FwOpcodeType opCode, | ||
U32 cmdSeq, | ||
const Fw::CmdResponse& response) { | ||
// Forward the command status | ||
this->forwardSeqCmdStatus_out(portNum, opCode, cmdSeq, response); | ||
Check warning Code scanning / CodeQL Unchecked function argument Warning
This use of parameter portNum has not been checked.
Check warning Code scanning / CodeQL Unchecked function argument Warning
This use of parameter opCode has not been checked.
Check warning Code scanning / CodeQL Unchecked function argument Warning
This use of parameter cmdSeq has not been checked.
Check warning Code scanning / CodeQL Unchecked function argument Warning
This use of parameter response has not been checked.
|
||
} | ||
|
||
} // end namespace Svc |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
|
||
module Svc { | ||
|
||
@ A component for splitting incoming commands to local or remote | ||
passive component CmdSplitter { | ||
|
||
# ---------------------------------------------------------------------- | ||
# General ports | ||
# ---------------------------------------------------------------------- | ||
|
||
@ Input port for local or remote commands | ||
sync input port CmdBuff: Fw.Com | ||
|
||
@ Input port for receiving the command status | ||
sync input port seqCmdStatus: Fw.CmdResponse | ||
|
||
@ Output port for forwarding the Command status | ||
output port forwardSeqCmdStatus: Fw.CmdResponse | ||
|
||
@ Output port for local commands | ||
output port LocalCmd: Fw.Com | ||
|
||
@ Output port for remote commands | ||
output port RemoteCmd: Fw.Com | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// ====================================================================== | ||
// \title CmdSplitter.hpp | ||
// \author watney | ||
// \brief hpp file for CmdSplitter component implementation class | ||
// ====================================================================== | ||
|
||
#ifndef CmdSplitter_HPP | ||
#define CmdSplitter_HPP | ||
|
||
#include <Fw/Cmd/CmdResponsePortAc.hpp> | ||
#include "Svc/CmdSplitter/CmdSplitterComponentAc.hpp" | ||
|
||
namespace Svc { | ||
|
||
class CmdSplitter : public CmdSplitterComponentBase { | ||
public: | ||
// ---------------------------------------------------------------------- | ||
// Construction, initialization, and destruction | ||
// ---------------------------------------------------------------------- | ||
|
||
//! Construct object CmdSplitter | ||
//! | ||
CmdSplitter(const char* const compName /*!< The component name*/ | ||
); | ||
|
||
//! Destroy object CmdSplitter | ||
//! | ||
~CmdSplitter(); | ||
|
||
PRIVATE : | ||
|
||
// ---------------------------------------------------------------------- | ||
// Handler implementations for user-defined typed input ports | ||
// ---------------------------------------------------------------------- | ||
|
||
//! Handler implementation for CmdBuff | ||
//! | ||
void CmdBuff_handler(const NATIVE_INT_TYPE portNum, /*!< The port number */ | ||
Fw::ComBuffer& data, /*!< Buffer containing packet data */ | ||
U32 context /*!< Call context value; meaning chosen by user */ | ||
); | ||
|
||
//! Handler implementation for seqCmdStatus | ||
//! | ||
void seqCmdStatus_handler(const NATIVE_INT_TYPE portNum, /*!< The port number */ | ||
FwOpcodeType opCode, /*!< Command Op Code */ | ||
U32 cmdSeq, /*!< Command Sequence */ | ||
const Fw::CmdResponse& response /*!< The command response argument */ | ||
); | ||
}; | ||
|
||
} // end namespace Svc | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
\page SvcCmdSplitter Svc::CmdSplitter Component | ||
# Svc::CmdSplitter Component | ||
|
||
## 1. Introduction | ||
|
||
The `Svc::CmdSplitter` splits an uplinked command execution to two separate `Svc::CmdDispatcher` components: one "local" and the other "remote". This splitting is done by opcode where local commands are commands whose opcode is less than `Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE` and remote commands are those opcodes equal to or larger than that configuration setting. `Svc::CmdSplitter` is intended to be used as part of the hub pattern to route command to a command dispatcher in the remote deployment. | ||
|
||
## 2. Requirements | ||
|
||
The requirements for `Svc::CmdSplitter` are as follows: | ||
|
||
| Requirement | Description | Verification Method | | ||
|----------------------|------------------------------------------------------------------------------------------------------|---------------------| | ||
| SVC-CMD-SPLITTER-001 | The `Svc::CmdSplitter` component shall accept incoming command buffers. | Unit Test | | ||
| SVC-CMD-SPLITTER-002 | The `Svc::CmdSplitter` component shall route commands under a configured value to the "local" port. | Unit Test | | ||
| SVC-CMD-SPLITTER-003 | The `Svc::CmdSplitter` component shall route commands under a configured value to the "remote" port. | Unit Test | | ||
| SVC-CMD-SPLITTER-004 | The `Svc::CmdSplitter` component shall route commands to the "local" port when an error occurs. | Unit Test | | ||
| SVC-CMD-SPLITTER-005 | The `Svc::CmdSplitter` forward command status responses. | Unit Test | | ||
|
||
## 3. Design | ||
|
||
### 3.1 Ports | ||
|
||
| Name | Type | Kind | Description | | ||
|---------------------|----------------|------------|-----------------------------------------------------------------| | ||
| CmdBuff | Fw.Com | sync input | Incoming command buffer. | | ||
| seqCmdStatus | Fw.CmdResponse | sync input | Incoming command status from both local and remote dispatchers. | | ||
| LocalCmd | Fw.Com | sync input | Outgoing command buffer for local command dispatcher. | | ||
| RemoteCmd | Fw.Com | sync input | Outgoing command buffer for remote command dispatcher. | | ||
| forwardSeqCmdStatus | Fw.CmdResponse | sync input | Outgoing forwarded command status. | | ||
|
||
### 3.2 Functional Description | ||
|
||
The `Svc::CmdSplitter` routes an incoming command buffer of type `Fw::ComBuffer` to a local or remote command dispatcher. This is done by comparing the command's opcode to the `Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE` configuration value. All command responses are forwarded through. | ||
|
||
### 3.1 State | ||
|
||
`Svc::CmdSplitter` has no state machines nor internal state. | ||
|
||
### 3.2 Algorithms | ||
|
||
`Svc::CmdSplitter` has no significant algorithms. | ||
|
||
## 4. Unit Testing | ||
|
||
To see unit test coverage run `fprime-util check --coverage` in the `Svc::CmdSplitter` directory | ||
|
||
## 5. Change Log | ||
|
||
| Date | Description | | ||
|------------|-------------| | ||
| 2023-06-12 | Initial | | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// ---------------------------------------------------------------------- | ||
// TestMain.cpp | ||
// ---------------------------------------------------------------------- | ||
|
||
#include "Tester.hpp" | ||
|
||
TEST(Nominal, Local) { | ||
Svc::Tester tester; | ||
tester.test_local_routing(); | ||
} | ||
|
||
TEST(Nominal, Remote) { | ||
Svc::Tester tester; | ||
tester.test_remote_routing(); | ||
} | ||
|
||
TEST(Nominal, Forwarding) { | ||
Svc::Tester tester; | ||
tester.test_response_forwarding(); | ||
} | ||
|
||
TEST(Error, BadCommands) { | ||
Svc::Tester tester; | ||
tester.test_error_routing(); | ||
} | ||
|
||
|
||
|
||
|
||
int main(int argc, char **argv) { | ||
::testing::InitGoogleTest(&argc, argv); | ||
return RUN_ALL_TESTS(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// ====================================================================== | ||
// \title CmdSplitter.hpp | ||
// \author mstarch | ||
// \brief cpp file for CmdSplitter test harness implementation class | ||
// ====================================================================== | ||
|
||
#include "Tester.hpp" | ||
#include <CmdSplitterCfg.hpp> | ||
#include <Fw/Cmd/CmdPacket.hpp> | ||
#include <Fw/Test/UnitTest.hpp> | ||
#include <STest/Pick/Pick.hpp> | ||
|
||
namespace Svc { | ||
|
||
// ---------------------------------------------------------------------- | ||
// Construction and destruction | ||
// ---------------------------------------------------------------------- | ||
|
||
Tester ::Tester() : CmdSplitterGTestBase("Tester", Tester::MAX_HISTORY_SIZE), component("CmdSplitter") { | ||
this->initComponents(); | ||
this->connectPorts(); | ||
} | ||
|
||
Tester ::~Tester() {} | ||
|
||
// ---------------------------------------------------------------------- | ||
// Tests | ||
// ---------------------------------------------------------------------- | ||
|
||
Fw::ComBuffer Tester ::build_command_around_opcode(FwOpcodeType opcode) { | ||
Fw::ComBuffer comBuffer; | ||
EXPECT_EQ(comBuffer.serialize(static_cast<FwPacketDescriptorType>(Fw::ComPacket::FW_PACKET_COMMAND)), Fw::FW_SERIALIZE_OK); | ||
EXPECT_EQ(comBuffer.serialize(opcode), Fw::FW_SERIALIZE_OK); | ||
|
||
Fw::CmdArgBuffer args; | ||
|
||
U32 random_size = STest::Pick::lowerUpper(0, args.getBuffCapacity()); | ||
args.resetSer(); | ||
for (FwSizeType i = 0; i < random_size; i++) { | ||
args.serialize(static_cast<U8>(STest::Pick::any())); | ||
} | ||
EXPECT_EQ(comBuffer.serialize(args), Fw::FW_SERIALIZE_OK); | ||
return comBuffer; | ||
} | ||
|
||
void Tester ::test_local_routing() { | ||
REQUIREMENT("SVC-CMD-SPLITTER-001"); | ||
REQUIREMENT("SVC-CMD-SPLITTER-002"); | ||
|
||
ASSERT_GT(Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE, 0); // Must leave some room for local commands | ||
FwOpcodeType local_opcode = static_cast<FwOpcodeType>(STest::Pick::lowerUpper( | ||
0, FW_MIN(Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE - 1, std::numeric_limits<FwOpcodeType>::max()))); | ||
Fw::ComBuffer testBuffer = this->build_command_around_opcode(local_opcode); | ||
|
||
U32 context = static_cast<U32>(STest::Pick::any()); | ||
this->invoke_to_CmdBuff(0, testBuffer, context); | ||
ASSERT_from_RemoteCmd_SIZE(0); | ||
ASSERT_from_LocalCmd_SIZE(1); | ||
ASSERT_from_LocalCmd(0, testBuffer, context); | ||
} | ||
|
||
void Tester ::test_remote_routing() { | ||
REQUIREMENT("SVC-CMD-SPLITTER-001"); | ||
REQUIREMENT("SVC-CMD-SPLITTER-003"); | ||
|
||
ASSERT_LT(Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE, | ||
std::numeric_limits<FwOpcodeType>::max()); // Must leave some room for remote commands | ||
FwOpcodeType local_opcode = static_cast<FwOpcodeType>( | ||
STest::Pick::lowerUpper(Svc::CMD_SPLITTER_REMOTE_OPCODE_BASE, std::numeric_limits<FwOpcodeType>::max())); | ||
Fw::ComBuffer testBuffer = this->build_command_around_opcode(local_opcode); | ||
|
||
U32 context = static_cast<U32>(STest::Pick::any()); | ||
this->invoke_to_CmdBuff(0, testBuffer, context); | ||
ASSERT_from_LocalCmd_SIZE(0); | ||
ASSERT_from_RemoteCmd_SIZE(1); | ||
ASSERT_from_RemoteCmd(0, testBuffer, context); | ||
} | ||
|
||
void Tester ::test_error_routing() { | ||
REQUIREMENT("SVC-CMD-SPLITTER-001"); | ||
REQUIREMENT("SVC-CMD-SPLITTER-004"); | ||
Fw::ComBuffer testBuffer; // Intentionally left empty | ||
U32 context = static_cast<U32>(STest::Pick::any()); | ||
this->invoke_to_CmdBuff(0, testBuffer, context); | ||
ASSERT_from_RemoteCmd_SIZE(0); | ||
ASSERT_from_LocalCmd_SIZE(1); | ||
ASSERT_from_LocalCmd(0, testBuffer, context); | ||
} | ||
|
||
void Tester ::test_response_forwarding() { | ||
REQUIREMENT("SVC-CMD-SPLITTER-001"); | ||
REQUIREMENT("SVC-CMD-SPLITTER-005"); | ||
|
||
FwOpcodeType opcode = | ||
static_cast<FwOpcodeType>(STest::Pick::lowerUpper(0, std::numeric_limits<FwOpcodeType>::max())); | ||
Fw::CmdResponse response; | ||
response.e = static_cast<Fw::CmdResponse::T>(STest::Pick::lowerUpper(0, Fw::CmdResponse::NUM_CONSTANTS)); | ||
U32 cmdSeq = static_cast<U32>(STest::Pick::any()); | ||
this->invoke_to_seqCmdStatus(0, opcode, cmdSeq, response); | ||
ASSERT_from_forwardSeqCmdStatus_SIZE(1); | ||
ASSERT_from_forwardSeqCmdStatus(0, opcode, cmdSeq, response); | ||
} | ||
|
||
// ---------------------------------------------------------------------- | ||
// Handlers for typed from ports | ||
// ---------------------------------------------------------------------- | ||
|
||
void Tester ::from_LocalCmd_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { | ||
this->pushFromPortEntry_LocalCmd(data, context); | ||
} | ||
|
||
void Tester ::from_RemoteCmd_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { | ||
this->pushFromPortEntry_RemoteCmd(data, context); | ||
} | ||
|
||
void Tester ::from_forwardSeqCmdStatus_handler(const NATIVE_INT_TYPE portNum, | ||
FwOpcodeType opCode, | ||
U32 cmdSeq, | ||
const Fw::CmdResponse& response) { | ||
this->pushFromPortEntry_forwardSeqCmdStatus(opCode, cmdSeq, response); | ||
} | ||
|
||
} // end namespace Svc |
Check notice
Code scanning / CodeQL
More than one statement per line Note