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

Update/arrayiffy cmd split #2287

Merged
merged 4 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 12 additions & 5 deletions Svc/CmdSplitter/CmdSplitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
#include <FpConfig.hpp>
#include <Fw/Cmd/CmdPacket.hpp>
#include <Svc/CmdSplitter/CmdSplitter.hpp>
#include <config/CmdSplitterCfg.hpp>
#include <Fw/Types/Assert.hpp>
#include <FppConstantsAc.hpp>

namespace Svc {

Expand All @@ -19,6 +20,10 @@ CmdSplitter ::CmdSplitter(const char* const compName) : CmdSplitterComponentBase

CmdSplitter ::~CmdSplitter() {}

void CmdSplitter ::configure(const FwOpcodeType remoteBaseOpcode) {
this->m_remoteBase = remoteBaseOpcode;
Dismissed Show dismissed Hide dismissed
}

// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
Expand All @@ -27,15 +32,16 @@ void CmdSplitter ::CmdBuff_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer&
Fw::CmdPacket cmdPkt;
Fw::SerializeStatus stat = cmdPkt.deserialize(data);

FW_ASSERT(portNum < CmdSplitterPorts);
if (stat != Fw::FW_SERIALIZE_OK) {
// Let the local command dispatcher deal with it
this->LocalCmd_out(0, data, context);
this->LocalCmd_out(portNum, data, context);
Fixed Show fixed Hide fixed
Dismissed Show dismissed Hide dismissed
} else {
// Check if local or remote
if (cmdPkt.getOpCode() < CMD_SPLITTER_REMOTE_OPCODE_BASE) {
this->LocalCmd_out(0, data, context);
if (cmdPkt.getOpCode() < this->m_remoteBase) {
this->LocalCmd_out(portNum, data, context);
Fixed Show fixed Hide fixed
Dismissed Show dismissed Hide dismissed
} else {
this->RemoteCmd_out(0, data, context);
this->RemoteCmd_out(portNum, data, context);
Fixed Show fixed Hide fixed
Dismissed Show dismissed Hide dismissed
}
}
}
Expand All @@ -44,6 +50,7 @@ void CmdSplitter ::seqCmdStatus_handler(const NATIVE_INT_TYPE portNum,
FwOpcodeType opCode,
U32 cmdSeq,
const Fw::CmdResponse& response) {
FW_ASSERT(portNum < CmdSplitterPorts);
// Forward the command status
this->forwardSeqCmdStatus_out(portNum, opCode, cmdSeq, response);
}
Expand Down
20 changes: 12 additions & 8 deletions Svc/CmdSplitter/CmdSplitter.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@ module Svc {
passive component CmdSplitter {

# ----------------------------------------------------------------------
# General ports
# Upstream connections: uplink commanding and command sequencers
# ----------------------------------------------------------------------

@ 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
sync input port CmdBuff: [CmdSplitterPorts] Fw.Com

@ Output port for forwarding the Command status
output port forwardSeqCmdStatus: Fw.CmdResponse
output port forwardSeqCmdStatus: [CmdSplitterPorts] Fw.CmdResponse

# ----------------------------------------------------------------------
# Downstream connections: local and remote command sequencers
# ----------------------------------------------------------------------

@ Input port for receiving the command status
sync input port seqCmdStatus: [CmdSplitterPorts] Fw.CmdResponse

@ Output port for local commands
output port LocalCmd: Fw.Com
output port LocalCmd: [CmdSplitterPorts] Fw.Com

@ Output port for remote commands
output port RemoteCmd: Fw.Com
output port RemoteCmd: [CmdSplitterPorts] Fw.Com

}
}
8 changes: 7 additions & 1 deletion Svc/CmdSplitter/CmdSplitter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ class CmdSplitter : public CmdSplitterComponentBase {
//!
~CmdSplitter();

PRIVATE :
//! Configure this splitter
//!
void configure(const FwOpcodeType remoteBaseOpcode /*!< Base remote opcode*/);

PRIVATE:

// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
Expand All @@ -47,6 +51,8 @@ class CmdSplitter : public CmdSplitterComponentBase {
U32 cmdSeq, /*!< Command Sequence */
const Fw::CmdResponse& response /*!< The command response argument */
);

FwOpcodeType m_remoteBase; // Opcodes greater than or equal than this value will route remotely
};

} // end namespace Svc
Expand Down
37 changes: 20 additions & 17 deletions Svc/CmdSplitter/docs/sdd.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,44 @@

## 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.
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 a configured base and remote commands are those opcodes equal to or larger than that configurated base 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.

All input and output are done through port arrays that mirror the port array of input commands to the command dispatcher. In this way `Svc::CmdSplitter` may support multiple command sources in the same manner that `Svc::CmdDispatcher` does.

## 2. Requirements

The requirements for `Svc::CmdSplitter` are as follows:

| Requirement | Description | Verification Method |
|----------------------|------------------------------------------------------------------------------------------------------|---------------------|
| SVC-CMD-SPLITTER-000 | The `Svc::CmdSplitter` component shall support multiple command sources. | Unit Test |
| 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 |
| SVC-CMD-SPLITTER-005 | The `Svc::CmdSplitter` component shall 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. |
| Name | Type | Kind | Description |
|---------------------|----------------|------------------|--------------------------------------------------------------------------|
| CmdBuff | Fw.Com | sync input array | Array of incoming command buffer. |
| seqCmdStatus | Fw.CmdResponse | sync input array | Array of incoming command status from both local and remote dispatchers. |
| LocalCmd | Fw.Com | output array | Array of outgoing command buffer for local command dispatcher. |
| RemoteCmd | Fw.Com | output array | Array of outgoing command buffer for remote command dispatcher. |
| forwardSeqCmdStatus | Fw.CmdResponse | output array | Array of outgoing forwarded command status. |

> Port arrays mirror those of the command dispatcher in order to support multiple sources in the same fashion that command dispatcher does.

### 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.
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 configured base opcode value. All command responses are forwarded through.

### 3.1 State

`Svc::CmdSplitter` has no state machines nor internal state.
`Svc::CmdSplitter` has only one internal state variable: `m_remoteBase` the configured base opcode for remote opcodes. This is set by a call to the `configure()` method at system start-up.

### 3.2 Algorithms

Expand All @@ -47,9 +52,7 @@ To see unit test coverage run `fprime-util check --coverage` in the `Svc::CmdSpl

## 5. Change Log

| Date | Description |
|------------|-------------|
| 2023-06-12 | Initial |



| Date | Description |
|------------|---------------------------------|
| 2023-06-12 | Initial |
| 2023-09-27 | Support multiple command inputs |
52 changes: 39 additions & 13 deletions Svc/CmdSplitter/test/ut/Tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
// ======================================================================

#include "Tester.hpp"
#include <CmdSplitterCfg.hpp>
#include <Fw/Cmd/CmdPacket.hpp>
#include <Fw/Test/UnitTest.hpp>
#include <STest/Pick/Pick.hpp>
#include "FppConstantsAc.hpp"

namespace Svc {

Expand Down Expand Up @@ -43,51 +43,71 @@ Fw::ComBuffer Tester ::build_command_around_opcode(FwOpcodeType opcode) {
return comBuffer;
}

FwOpcodeType Tester ::setup_and_pick_valid_opcode(bool for_local) {
const FwOpcodeType MAX_OPCODE = std::numeric_limits<FwOpcodeType>::max();
if (for_local) {
FwOpcodeType base = STest::Pick::lowerUpper(1, MAX_OPCODE);
component.configure(base);
EXPECT_GT(base, 0); // Must leave some room for local commands
return static_cast<FwOpcodeType>(
STest::Pick::lowerUpper(0, FW_MIN(base - 1, MAX_OPCODE))
);
}
FwOpcodeType base = STest::Pick::lowerUpper(0, MAX_OPCODE);
component.configure(base);
return static_cast<FwOpcodeType>(STest::Pick::lowerUpper(base, MAX_OPCODE));
}

void Tester ::test_local_routing() {
REQUIREMENT("SVC-CMD-SPLITTER-000");
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())));
FwOpcodeType local_opcode = this->setup_and_pick_valid_opcode(true);
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);
this->active_command_source = static_cast<NATIVE_INT_TYPE>(STest::Pick::lowerUpper(
0, CmdSplitterPorts));
this->invoke_to_CmdBuff(this->active_command_source, 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-000");
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);
FwOpcodeType remote_opcode = this->setup_and_pick_valid_opcode(false);
Fw::ComBuffer testBuffer = this->build_command_around_opcode(remote_opcode);

U32 context = static_cast<U32>(STest::Pick::any());
this->invoke_to_CmdBuff(0, testBuffer, context);
this->active_command_source = static_cast<NATIVE_INT_TYPE>(STest::Pick::lowerUpper(
0, CmdSplitterPorts));
this->invoke_to_CmdBuff(this->active_command_source, 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-000");
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);
this->active_command_source = static_cast<NATIVE_INT_TYPE>(STest::Pick::lowerUpper(
0, CmdDispatcherSequencePorts));
this->invoke_to_CmdBuff(this->active_command_source, 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-000");
REQUIREMENT("SVC-CMD-SPLITTER-001");
REQUIREMENT("SVC-CMD-SPLITTER-005");

Expand All @@ -96,7 +116,10 @@ void Tester ::test_response_forwarding() {
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);
this->active_command_source = static_cast<NATIVE_INT_TYPE>(STest::Pick::lowerUpper(
0, CmdDispatcherSequencePorts));

this->invoke_to_seqCmdStatus(this->active_command_source, opcode, cmdSeq, response);
ASSERT_from_forwardSeqCmdStatus_SIZE(1);
ASSERT_from_forwardSeqCmdStatus(0, opcode, cmdSeq, response);
}
Expand All @@ -106,17 +129,20 @@ void Tester ::test_response_forwarding() {
// ----------------------------------------------------------------------

void Tester ::from_LocalCmd_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) {
EXPECT_EQ(this->active_command_source, portNum) << "Command source not respected";
this->pushFromPortEntry_LocalCmd(data, context);
}

void Tester ::from_RemoteCmd_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) {
EXPECT_EQ(this->active_command_source, portNum) << "Command source not respected";
this->pushFromPortEntry_RemoteCmd(data, context);
}

void Tester ::from_forwardSeqCmdStatus_handler(const NATIVE_INT_TYPE portNum,
FwOpcodeType opCode,
U32 cmdSeq,
const Fw::CmdResponse& response) {
EXPECT_EQ(this->active_command_source, portNum) << "Command source not respected";
this->pushFromPortEntry_forwardSeqCmdStatus(opCode, cmdSeq, response);
}

Expand Down
5 changes: 5 additions & 0 deletions Svc/CmdSplitter/test/ut/Tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ class Tester : public CmdSplitterGTestBase {
//!
Fw::ComBuffer build_command_around_opcode(FwOpcodeType opcode);

//! Helper to set opcode base and select a valid opcode
//!
FwOpcodeType setup_and_pick_valid_opcode(bool for_local /*!< Local command testing*/);

// ----------------------------------------------------------------------
// Handlers for typed from ports
// ----------------------------------------------------------------------
Expand Down Expand Up @@ -104,6 +108,7 @@ class Tester : public CmdSplitterGTestBase {
//! The component under test
//!
CmdSplitter component;
NATIVE_INT_TYPE active_command_source;
};

} // end namespace Svc
Expand Down
1 change: 1 addition & 0 deletions cmake/FPrime-Code.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ endif()
add_library(Fpp INTERFACE)
set(FPRIME_CURRENT_MODULE config)
add_subdirectory("${FPRIME_CONFIG_DIR}" "${CMAKE_BINARY_DIR}/config")
include_directories("${CMAKE_BINARY_DIR}/config")
set(_FP_CORE_PACKAGES Fw Svc Os Drv CFDP Utils)
foreach (_FP_PACKAGE_DIR IN LISTS _FP_CORE_PACKAGES)
set(FPRIME_CURRENT_MODULE "${_FP_PACKAGE_DIR}")
Expand Down
3 changes: 3 additions & 0 deletions config/AcConstants.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ constant CmdDispatcherComponentCommandPorts = 30
@ Used for uplink/sequencer buffer/response ports
constant CmdDispatcherSequencePorts = 5

@ Used for sizing the command splitter input arrays
constant CmdSplitterPorts = CmdDispatcherSequencePorts

@ Number of static memory allocations
constant StaticMemoryAllocations = 4

Expand Down
18 changes: 0 additions & 18 deletions config/CmdSplitterCfg.hpp

This file was deleted.