Skip to content
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

Merged
merged 2 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Svc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComSplitter/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComStub/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdDispatcher/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdSequencer/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdSplitter/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Deframer/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FatalHandler/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlinkPorts/")
Expand Down
15 changes: 15 additions & 0 deletions Svc/CmdSplitter/CMakeLists.txt
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()
51 changes: 51 additions & 0 deletions Svc/CmdSplitter/CmdSplitter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// ======================================================================
// \title CmdSplitter.cpp
// \author watney

Check failure on line 3 in Svc/CmdSplitter/CmdSplitter.cpp

View workflow job for this annotation

GitHub Actions / Spell checking

`watney` is not a recognized word. (unrecognized-spelling)
// \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

More than one statement per line Note

This line contains 2 statements; only one is allowed.

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
27 changes: 27 additions & 0 deletions Svc/CmdSplitter/CmdSplitter.fpp
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

}
}
54 changes: 54 additions & 0 deletions Svc/CmdSplitter/CmdSplitter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// ======================================================================
// \title CmdSplitter.hpp
// \author watney

Check failure on line 3 in Svc/CmdSplitter/CmdSplitter.hpp

View workflow job for this annotation

GitHub Actions / Spell checking

`watney` is not a recognized word. (unrecognized-spelling)
// \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
55 changes: 55 additions & 0 deletions Svc/CmdSplitter/docs/sdd.md
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 |



33 changes: 33 additions & 0 deletions Svc/CmdSplitter/test/ut/TestMain.cpp
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();
}
123 changes: 123 additions & 0 deletions Svc/CmdSplitter/test/ut/Tester.cpp
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