mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 16:29:04 -06:00
Add Framer FPP interface, implement FprimeFramer and adapt ComQueue (#3486)
* Initial FprimeFramer and FprimePacketizer * Code clarity + set up UTs * Rework ComQueue and ComStub to use DataWithContext * Add packets to RefPackets.fppi * Fix ComQueue tests * Add hotfix to FileDownlink instead of ComQueue * Fix cancelPacket as well * Fix ComQueue UTs by removing hotfix * Refactor DataWithContext to use an FPP object for context instead of Fw.Buffer * Touch up testing * Add docs * more docs * More docs * Rework buffer deallocation pattern to pass-through ComQueue * Update ComStub UTs * Restore original FileDownlink.cpp * Formatting tweak * Update deprecated getSerializeRepr() calls * deserialization methods * Fix spelling * add cast for safety * CMakefile change * Bump ComQueue depth * Update RPI deployment with new Downlink stack * Rename comQueueIn port to comPktQueueIn * Fix comQueueIn to comPktQueueIn change * Remove legacy Svc.Framer * Fix CMake UTs * Fix RPI topology config * Fix FprimeProtocol.fpp module * Fix namespacing * Use const reference for FrameContext port * Review comments EXCEPT port passback refactor * Rework ComStub with new ByteStream * New ByteStream - ComInterface model * Rework TcpClient / TcpServer with new bytestream * Adapt UDP component for new ByteStream * Adapt FrameAccumulator for new ByteStream * Adapt FprimeFramer for new ByteStream * Update Ref topology with new ByteStream model * Remove all legacy deallocates from Drivers; reintroduce DEPRECATED model types * Fix spelling and include error * More spelling.... * RPI and RpiDemo fixes * Fix conversion warning on RPI * static_cast for short int on RPI * Standardize port names * Remove legacy Drv types and merge RECV/SEND enum type, delete StreamCrossover * Update SDDs * Update SDDs * Fix ComInterface <-> Framer interfaction, clarify comments and fix annotations * Switch ComStub from ASSERT to log failure and return buffer * Add history size check + clarify test handler overrides * Fix RPI topology to wire comStub on Uplink * Rename comm to comDriver in RPI topology * Update communication adapter interface docs
This commit is contained in:
parent
a9da1b9955
commit
d0246f148b
3
.github/actions/spelling/expect.txt
vendored
3
.github/actions/spelling/expect.txt
vendored
@ -86,9 +86,9 @@ BUFFERALLOCATIONFAILED
|
||||
BUFFERGETOUT
|
||||
BUFFERMANAGERCOMPONENTIMPLCFG
|
||||
BUFFERMGR
|
||||
BUFFERQUEUEIN
|
||||
BUFFERTOOSMALLFORDATA
|
||||
BUFFERTOOSMALLFORPACKET
|
||||
BUFFQUEUEIN
|
||||
buffsize
|
||||
BUGLIST
|
||||
bugprone
|
||||
@ -156,6 +156,7 @@ COMMANDDISPATCHERIMPLCFG
|
||||
commandline
|
||||
commasepitem
|
||||
COMPACKET
|
||||
COMPACKETQUEUEIN
|
||||
COMPONENTTESTERIMPL
|
||||
COMQUEUE
|
||||
COMQUEUEIN
|
||||
|
||||
9
.github/actions/spelling/patterns.txt
vendored
9
.github/actions/spelling/patterns.txt
vendored
@ -137,3 +137,12 @@ TeX/AMS
|
||||
|
||||
# ignore long runs of a single character:
|
||||
\b([A-Za-z])\g{-1}{3,}\b
|
||||
|
||||
|
||||
##########################################
|
||||
###### F Prime specific patterns ######
|
||||
##########################################
|
||||
|
||||
# .get...() .set...() autocoded functions
|
||||
\.get\w+\(
|
||||
\.set\w+\(
|
||||
|
||||
@ -1,40 +1,22 @@
|
||||
module Drv {
|
||||
|
||||
@ Status returned by the send call
|
||||
enum SendStatus {
|
||||
SEND_OK = 0 @< Send worked as expected
|
||||
SEND_RETRY = 1 @< Data send should be retried
|
||||
SEND_ERROR = 2 @< Send error occurred retrying may succeed
|
||||
enum ByteStreamStatus {
|
||||
OP_OK @< Operation worked as expected
|
||||
SEND_RETRY @< Data send should be retried
|
||||
RECV_NO_DATA @< Receive worked, but there was no data
|
||||
OTHER_ERROR @< Error occurred, retrying may succeed
|
||||
}
|
||||
|
||||
@ Send data out through the byte stream
|
||||
port ByteStreamSend(
|
||||
ref sendBuffer: Fw.Buffer @< Data to send
|
||||
) -> SendStatus
|
||||
|
||||
@ Status associated with the received data
|
||||
enum RecvStatus {
|
||||
RECV_OK = 0 @< Receive worked as expected
|
||||
RECV_NO_DATA = 1 @< Receive worked, but there was no data
|
||||
RECV_ERROR = 2 @< Receive error occurred retrying may succeed
|
||||
}
|
||||
|
||||
@ Carries the received bytes stream driver
|
||||
port ByteStreamRecv(
|
||||
ref recvBuffer: Fw.Buffer
|
||||
recvStatus: RecvStatus
|
||||
@ Port to exchange buffer and status with the ByteStreamDriver model
|
||||
@ This port is used for receiving data from the driver as well as on
|
||||
@ callback of a send call
|
||||
port ByteStreamData(
|
||||
ref buffer: Fw.Buffer,
|
||||
status: ByteStreamStatus
|
||||
)
|
||||
|
||||
enum PollStatus {
|
||||
POLL_OK = 0 @< Poll successfully received data
|
||||
POLL_RETRY = 1 @< No data available, retry later
|
||||
POLL_ERROR = 2 @< Error received when polling
|
||||
}
|
||||
|
||||
port ByteStreamPoll(
|
||||
ref pollBuffer: Fw.Buffer
|
||||
) -> PollStatus
|
||||
|
||||
@ Signal indicating the driver is ready to send and received data
|
||||
port ByteStreamReady()
|
||||
|
||||
}
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
Old Symbol
|
||||
New Symbol
|
||||
|
||||
Drv::POLL_OK
|
||||
Drv::PollStatus::POLL_OK
|
||||
|
||||
Drv::POLL_RETRY
|
||||
Drv::PollStatus::POLL_RETRY
|
||||
|
||||
Drv::POLL_ERROR
|
||||
Drv::PollStatus::POLL_ERROR
|
||||
|
||||
Drv::RECV_OK
|
||||
Drv::RecvStatus::RECV_OK
|
||||
|
||||
Drv::RECV_ERROR
|
||||
Drv::RecvStatus::RECV_ERROR
|
||||
|
||||
Drv::SEND_OK
|
||||
Drv::SendStatus::SEND_OK
|
||||
|
||||
Drv::SEND_RETRY
|
||||
Drv::SendStatus::SEND_RETRY
|
||||
|
||||
Drv::SEND_ERROR
|
||||
Drv::SendStatus::SEND_ERROR
|
||||
@ -1,57 +1,40 @@
|
||||
# Drv::ByteStreamDriverModel Byte Stream Driver Model
|
||||
|
||||
The byte stream driver is a generic model for drivers implementing a "stream of bytes" interface. Typically these
|
||||
drivers operate with an outgoing stream and an incoming stream. The outgoing stream is represented by the "send" port
|
||||
and the incoming stream is either polled using the "poll" port or return asynchronously via the "readCallback" port.
|
||||
The byte stream driver is a generic model for drivers implementing a "stream of bytes" interface. Typically these drivers operate with an outgoing stream and an incoming stream.
|
||||
The outgoing stream is represented by the input `send` port; other components can invoke this port to send data through the driver. The incoming stream is represented by the output `recv` port; the driver will call this port to send data to the component that is receiving data from the driver.
|
||||
|
||||
## Design
|
||||
|
||||
The manager component (typically the ground interface) initiates the transfer of send data by calling the "send" port.
|
||||
The caller will provide a `Fw::Buffer` containing the data to send and the port call will return a status of that send.
|
||||
### Send
|
||||
|
||||
The manager component (for example a radio manager) initiates the transfer of send data by calling the "send" port.
|
||||
The caller will provide a `Fw::Buffer` containing the data to send. The driver component **must** perform a callback on its `dataReturnOut` port to return the status of that send as well as returning ownership of the `Fw::Buffer` to the caller.
|
||||
These responses are an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description | Buffer Ownership |
|
||||
|---|---|---|
|
||||
| Drv::SEND_OK | Send functioned normally. | Ownership of the `Fw::Buffer` passes to the byte stream driver. |
|
||||
| Drv::SEND_RETRY | Send should be retried, but a subsequent send should return SEND_OK. | The caller retains ownership of the `Fw::Buffer`. |
|
||||
| Drv::SEND_ERROR | Send produced an error, future sends likely to fail. | Ownership of the `Fw::Buffer` passes to the byte stream driver. |
|
||||
| ByteStreamStatus::OP_OK | Send functioned normally. | Ownership of the `Fw::Buffer` passes to the byte stream driver. |
|
||||
| ByteStreamStatus::SEND_RETRY | Send should be retried, but a subsequent send should return OP_OK. | The caller retains ownership of the `Fw::Buffer`. |
|
||||
| ByteStreamStatus::OTHER_ERROR | Send produced an error, future sends likely to fail. | Ownership of the `Fw::Buffer` passes to the byte stream driver. |
|
||||
|
||||
**Note:** in either formation described below, send will operate as described here.
|
||||
|
||||
### Callback Formation
|
||||
### Receive
|
||||
|
||||

|
||||
|
||||
In the callback formation, the byte stream driver component initiates the transfer of received data by calling the
|
||||
"readCallback" output port. This port transfers any read data in a `Fw::Buffer` along with a status for the receive.
|
||||
"recv" output port. This port transfers any read data in a `Fw::Buffer` along with a status for the receive.
|
||||
This status is an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| Drv::RECV_OK | Receive functioned normally buffer contains valid data. |
|
||||
| Drv::RECV_ERROR | Receive produced an error and buffer contains no valid data. |
|
||||
| ByteStreamStatus::OP_OK | Receive functioned normally and buffer contains valid data. |
|
||||
| ByteStreamStatus::RECV_NO_DATA | Receive worked, but there was no data |
|
||||
| ByteStreamStatus::OTHER_ERROR | Receive produced an error and buffer contains no valid data. |
|
||||
|
||||
The following components implement the byte stream model using a callback formation:
|
||||
- `DrvTcpClient`: a F´ component wrapper of the tcp client
|
||||
- `DrvTcpServer`: a F´ component wrapper of the tcp server
|
||||
- `DrvUdp`: a F´ component wrapper of the udp
|
||||
|
||||
### Polling Formation
|
||||
|
||||

|
||||
|
||||
In the polling formation, the manager component (typically the ground interface) initiates the transfer of received
|
||||
data by calling the "poll" input port. This port fills in the provided `Fw::Buffer` along with a status for the poll.
|
||||
This status is an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| Drv::POLL_OK | Poll functioned normally buffer contains valid data. |
|
||||
| Drv::POLL_RETRY | Poll should be retried and a subsequent send should return POLL_OK. |
|
||||
| Drv::POLL_ERROR | Poll produced an error and buffer contains no valid data. |
|
||||
|
||||
**Note:** there are no known implementers of the polling formation, although this formation is best suited for
|
||||
implementations running on baremetal machines.
|
||||
- [`Drv::TcpClient`](../../TcpClient/docs/sdd.md): a F´ component wrapper of the tcp client
|
||||
- [`Drv::TcpServer`](../../TcpServer/docs/sdd.md): a F´ component wrapper of the tcp server
|
||||
- [`Drv::Udp`](../../Udp/docs/sdd.md): a F´ component wrapper of the udp
|
||||
|
||||
## Class Diagram
|
||||

|
||||
@ -61,5 +44,4 @@ implementations running on baremetal machines.
|
||||
| Name | Description | Validation |
|
||||
|---|---|---|
|
||||
| BYTEDRV-001 | The ByteStreamDriverModel shall provide the capability to send bytes | inspection |
|
||||
| BYTEDRV-002 | The ByteStreamDriverModel shall provide the capability to poll for bytes | inspection |
|
||||
| BYTEDRV-003 | The ByteStreamDriverModel shall provide the capability to produce bytes | inspection |
|
||||
| BYTEDRV-002 | The ByteStreamDriverModel shall provide the capability to produce bytes | inspection |
|
||||
|
||||
@ -10,7 +10,6 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxGpioDriver/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxUartDriver/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxSpiDriver/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriver/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/StreamCrossover/")
|
||||
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ip/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TcpClient/")
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
@ Port invoked when the driver is ready to send/receive data
|
||||
output port ready: Drv.ByteStreamReady
|
||||
|
||||
@ Port invoked when driver has received data
|
||||
output port $recv: Drv.ByteStreamRecv
|
||||
@ Port invoked by the driver when it receives data
|
||||
output port $recv: Drv.ByteStreamData
|
||||
|
||||
@ Port invoked to send data out the driver
|
||||
guarded input port $send: Drv.ByteStreamSend
|
||||
@ Invoke this port to send data out the driver
|
||||
guarded input port $send: Fw.BufferSend
|
||||
|
||||
@ Port invoked to return ownership of sent data back to the sender
|
||||
output port dataReturnOut: Drv.ByteStreamData
|
||||
|
||||
@ -292,10 +292,10 @@ LinuxUartDriver ::~LinuxUartDriver() {
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Drv::SendStatus LinuxUartDriver ::send_handler(const FwIndexType portNum, Fw::Buffer& serBuffer) {
|
||||
Drv::SendStatus status = Drv::SendStatus::SEND_OK;
|
||||
void LinuxUartDriver ::send_handler(const FwIndexType portNum, Fw::Buffer& serBuffer) {
|
||||
Drv::ByteStreamStatus status = Drv::ByteStreamStatus::OP_OK;
|
||||
if (this->m_fd == -1 || serBuffer.getData() == nullptr || serBuffer.getSize() == 0) {
|
||||
status = Drv::SendStatus::SEND_ERROR;
|
||||
status = Drv::ByteStreamStatus::OTHER_ERROR;
|
||||
} else {
|
||||
unsigned char *data = serBuffer.getData();
|
||||
FW_ASSERT(static_cast<size_t>(serBuffer.getSize()) <= std::numeric_limits<size_t>::max(),
|
||||
@ -307,28 +307,25 @@ Drv::SendStatus LinuxUartDriver ::send_handler(const FwIndexType portNum, Fw::Bu
|
||||
if (-1 == stat || static_cast<size_t>(stat) != xferSize) {
|
||||
Fw::LogStringArg _arg = this->m_device;
|
||||
this->log_WARNING_HI_WriteError(_arg, static_cast<I32>(stat));
|
||||
status = Drv::SendStatus::SEND_ERROR;
|
||||
status = Drv::ByteStreamStatus::OTHER_ERROR;
|
||||
}
|
||||
}
|
||||
// Deallocate when necessary
|
||||
if (isConnected_deallocate_OutputPort(0)) {
|
||||
deallocate_out(0, serBuffer);
|
||||
}
|
||||
return status;
|
||||
// Return the buffer back to the caller
|
||||
dataReturnOut_out(0, serBuffer, status);
|
||||
}
|
||||
|
||||
void LinuxUartDriver ::serialReadTaskEntry(void* ptr) {
|
||||
FW_ASSERT(ptr != nullptr);
|
||||
Drv::RecvStatus status = RecvStatus::RECV_ERROR; // added by m.chase 03.06.2017
|
||||
Drv::ByteStreamStatus status = ByteStreamStatus::OTHER_ERROR; // added by m.chase 03.06.2017
|
||||
LinuxUartDriver* comp = reinterpret_cast<LinuxUartDriver*>(ptr);
|
||||
while (!comp->m_quitReadThread) {
|
||||
Fw::Buffer buff = comp->allocate_out(0,comp->m_allocationSize);
|
||||
|
||||
// On failed allocation, error and deallocate
|
||||
// On failed allocation, error
|
||||
if (buff.getData() == nullptr) {
|
||||
Fw::LogStringArg _arg = comp->m_device;
|
||||
comp->log_WARNING_HI_NoBuffers(_arg);
|
||||
status = RecvStatus::RECV_ERROR;
|
||||
status = ByteStreamStatus::OTHER_ERROR;
|
||||
comp->recv_out(0, buff, status);
|
||||
// to avoid spinning, wait 50 ms
|
||||
Os::Task::delay(Fw::TimeInterval(0, 50000));
|
||||
@ -350,12 +347,12 @@ void LinuxUartDriver ::serialReadTaskEntry(void* ptr) {
|
||||
if (stat == -1) {
|
||||
Fw::LogStringArg _arg = comp->m_device;
|
||||
comp->log_WARNING_HI_ReadError(_arg, stat);
|
||||
status = RecvStatus::RECV_ERROR;
|
||||
status = ByteStreamStatus::OTHER_ERROR;
|
||||
} else if (stat > 0) {
|
||||
buff.setSize(static_cast<U32>(stat));
|
||||
status = RecvStatus::RECV_OK; // added by m.chase 03.06.2017
|
||||
status = ByteStreamStatus::OP_OK; // added by m.chase 03.06.2017
|
||||
} else {
|
||||
status = RecvStatus::RECV_ERROR; // Simply to return the buffer
|
||||
status = ByteStreamStatus::OTHER_ERROR; // Simply to return the buffer
|
||||
}
|
||||
comp->recv_out(0, buff, status); // added by m.chase 03.06.2017
|
||||
}
|
||||
|
||||
@ -11,9 +11,6 @@ module Drv {
|
||||
@ Allocation port used for allocating memory in the receive task
|
||||
output port allocate: Fw.BufferGet
|
||||
|
||||
@ Deallocates buffers passed to the "send" port
|
||||
output port deallocate: Fw.BufferSend
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Special ports
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ -93,7 +93,7 @@ class LinuxUartDriver final : public LinuxUartDriverComponentBase {
|
||||
|
||||
//! Handler implementation for serialSend
|
||||
//!
|
||||
Drv::SendStatus send_handler(FwIndexType portNum, /*!< The port number*/
|
||||
void send_handler(FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer& serBuffer);
|
||||
|
||||
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
####
|
||||
# F prime CMakeLists.txt:
|
||||
#
|
||||
# SOURCE_FILES: combined list of source and autocoding files
|
||||
# MOD_DEPS: (optional) module dependencies
|
||||
#
|
||||
####
|
||||
set(SOURCE_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/StreamCrossover.fpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/StreamCrossover.cpp"
|
||||
)
|
||||
|
||||
register_fprime_module()
|
||||
|
||||
# Register the unit test build
|
||||
set(UT_SOURCE_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/StreamCrossover.fpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/test/ut/StreamCrossoverTester.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/test/ut/StreamCrossoverTestMain.cpp"
|
||||
)
|
||||
set(UT_AUTO_HELPERS ON)
|
||||
register_fprime_ut()
|
||||
@ -1,57 +0,0 @@
|
||||
// ======================================================================
|
||||
// \title StreamCrossover.cpp
|
||||
// \author ethanchee
|
||||
// \brief cpp file for StreamCrossover component implementation class
|
||||
// ======================================================================
|
||||
|
||||
|
||||
#include <Drv/StreamCrossover/StreamCrossover.hpp>
|
||||
#include <Fw/FPrimeBasicTypes.hpp>
|
||||
|
||||
namespace Drv {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction, initialization, and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
StreamCrossover ::
|
||||
StreamCrossover(
|
||||
const char *const compName
|
||||
) : StreamCrossoverComponentBase(compName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
StreamCrossover ::
|
||||
~StreamCrossover()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void StreamCrossover ::
|
||||
streamIn_handler(
|
||||
const FwIndexType portNum,
|
||||
Fw::Buffer &recvBuffer,
|
||||
const Drv::RecvStatus &recvStatus
|
||||
)
|
||||
{
|
||||
if(recvStatus == Drv::RecvStatus::RECV_ERROR || recvBuffer.getSize() == 0)
|
||||
{
|
||||
this->log_WARNING_HI_StreamOutError(Drv::SendStatus::SEND_ERROR);
|
||||
this->errorDeallocate_out(0, recvBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
Drv::SendStatus sendStatus = this->streamOut_out(0, recvBuffer);
|
||||
|
||||
if(sendStatus != Drv::SendStatus::SEND_OK)
|
||||
{
|
||||
this->log_WARNING_HI_StreamOutError(sendStatus);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Drv
|
||||
@ -1,28 +0,0 @@
|
||||
module Drv {
|
||||
|
||||
passive component StreamCrossover {
|
||||
|
||||
output port streamOut: Drv.ByteStreamSend
|
||||
|
||||
sync input port streamIn: Drv.ByteStreamRecv
|
||||
|
||||
@ Indicates buffer failed to send to streamOut.
|
||||
event StreamOutError(sendStatus: Drv.SendStatus) \
|
||||
severity warning high \
|
||||
format "StreamCrossover StreamOut Error: {}"
|
||||
|
||||
@ Allows for deallocation after bad receive status
|
||||
output port errorDeallocate: Fw.BufferSend
|
||||
|
||||
@ Port for requesting the current time
|
||||
time get port timeCaller
|
||||
|
||||
@ Port for sending textual representation of events
|
||||
text event port logTextOut
|
||||
|
||||
@ Port for sending events to downlink
|
||||
event port logOut
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
// ======================================================================
|
||||
// \title StreamCrossover.hpp
|
||||
// \author ethanchee
|
||||
// \brief hpp file for StreamCrossover component implementation class
|
||||
// ======================================================================
|
||||
|
||||
#ifndef StreamCrossover_HPP
|
||||
#define StreamCrossover_HPP
|
||||
|
||||
#include "Drv/StreamCrossover/StreamCrossoverComponentAc.hpp"
|
||||
|
||||
namespace Drv {
|
||||
|
||||
class StreamCrossover final :
|
||||
public StreamCrossoverComponentBase
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction, initialization, and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Construct object StreamCrossover
|
||||
//!
|
||||
StreamCrossover(
|
||||
const char *const compName /*!< The component name*/
|
||||
);
|
||||
|
||||
//! Destroy object StreamCrossover
|
||||
//!
|
||||
~StreamCrossover();
|
||||
|
||||
PRIVATE:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Handler implementation for streamIn
|
||||
//!
|
||||
void streamIn_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &recvBuffer,
|
||||
const Drv::RecvStatus &recvStatus
|
||||
);
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Drv
|
||||
|
||||
#endif
|
||||
@ -1,29 +0,0 @@
|
||||
# Drv::StreamCrossover Stream Crossover Component
|
||||
|
||||
The Stream Crossover component allows a connection of byte stream driver model ports of type ByteStreamRecv and
|
||||
ByteStreamSend.
|
||||
|
||||
## Design
|
||||
|
||||
The Drv::StreamCrossover utilizes the byte stream driver model to handle the incoming stream of bytes. Upon calling
|
||||
the "streamIn" port, the `Fw::Buffer` containing the data will be forwarded to the "streamOut" port. This enables a
|
||||
connection from a ByteStreamRecv port to a ByteStreamSend port.
|
||||
|
||||
## Port Descriptions
|
||||
| Name | Description |
|
||||
|---|---|
|
||||
| streamOut | A ByteStreamSend port for outgoing data stored in `Fw::Buffer` |
|
||||
| streamIn | A ByteStreamRecv port for incoming data stored in `Fw::Buffer` |
|
||||
| errorDeallocate | Deallocate a `Fw::Buffer` on error |
|
||||
|
||||
## Requirements
|
||||
Add requirements in the chart below
|
||||
| Name | Description | Validation |
|
||||
|---|---|---|
|
||||
| STREAM-CROSSOVER-COMP-001 | The stream crossover component shall provide the capability to forward bytes | Unit Test |
|
||||
|
||||
## Change Log
|
||||
| Date | Description |
|
||||
|---|---|
|
||||
| 2023-06-05 | Initial Draft |
|
||||
| 2023-06-09 | Implement Error Handling |
|
||||
@ -1,20 +0,0 @@
|
||||
// ----------------------------------------------------------------------
|
||||
// TestMain.cpp
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#include "StreamCrossoverTester.hpp"
|
||||
|
||||
TEST(Nominal, TestBuffer) {
|
||||
Drv::StreamCrossoverTester tester;
|
||||
tester.sendTestBuffer();
|
||||
}
|
||||
|
||||
TEST(Nominal, TestFail) {
|
||||
Drv::StreamCrossoverTester tester;
|
||||
tester.testFail();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
// ======================================================================
|
||||
// \title StreamCrossover.hpp
|
||||
// \author ethanchee
|
||||
// \brief cpp file for StreamCrossover test harness implementation class
|
||||
// ======================================================================
|
||||
|
||||
#include "StreamCrossoverTester.hpp"
|
||||
|
||||
namespace Drv {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
StreamCrossoverTester ::
|
||||
StreamCrossoverTester() :
|
||||
StreamCrossoverGTestBase("Tester", StreamCrossoverTester::MAX_HISTORY_SIZE),
|
||||
component("StreamCrossover")
|
||||
{
|
||||
this->initComponents();
|
||||
this->connectPorts();
|
||||
}
|
||||
|
||||
StreamCrossoverTester ::
|
||||
~StreamCrossoverTester()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void StreamCrossoverTester ::
|
||||
sendTestBuffer()
|
||||
{
|
||||
U8 testStr[6] = "test\n";
|
||||
Fw::Buffer sendBuffer(testStr, sizeof(testStr));
|
||||
this->invoke_to_streamIn(0, sendBuffer, Drv::RecvStatus::RECV_OK);
|
||||
|
||||
// Ensure only one buffer was sent to streamOut
|
||||
ASSERT_from_streamOut_SIZE(1);
|
||||
|
||||
// Ensure the sendBuffer was sent
|
||||
ASSERT_from_streamOut(0, sendBuffer);
|
||||
}
|
||||
|
||||
void StreamCrossoverTester ::
|
||||
testFail()
|
||||
{
|
||||
U8 testStr[6] = "test\n";
|
||||
Fw::Buffer sendBuffer(testStr, sizeof(testStr));
|
||||
this->invoke_to_streamIn(0, sendBuffer, Drv::RecvStatus::RECV_ERROR);
|
||||
|
||||
// Ensure only one buffer was sent to errorDeallocate port on RECV_ERROR
|
||||
ASSERT_from_errorDeallocate_SIZE(1);
|
||||
|
||||
// Ensure the sendBuffer was sent
|
||||
ASSERT_from_errorDeallocate(0, sendBuffer);
|
||||
|
||||
// Ensure the error event was sent
|
||||
ASSERT_EVENTS_StreamOutError_SIZE(1);
|
||||
|
||||
// Ensure the error is SEND_ERROR
|
||||
ASSERT_EVENTS_StreamOutError(0, Drv::SendStatus::SEND_ERROR);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Drv::SendStatus StreamCrossoverTester ::
|
||||
from_streamOut_handler(
|
||||
const FwIndexType portNum,
|
||||
Fw::Buffer &sendBuffer
|
||||
)
|
||||
{
|
||||
this->pushFromPortEntry_streamOut(sendBuffer);
|
||||
|
||||
U8 testStr[6] = "test\n";
|
||||
Fw::Buffer cmpBuffer(testStr, sizeof(testStr));
|
||||
|
||||
if(!(cmpBuffer == sendBuffer))
|
||||
{
|
||||
return Drv::SendStatus::SEND_ERROR;
|
||||
}
|
||||
|
||||
return Drv::SendStatus::SEND_OK;
|
||||
}
|
||||
|
||||
void StreamCrossoverTester ::
|
||||
from_errorDeallocate_handler(
|
||||
const FwIndexType portNum,
|
||||
Fw::Buffer &fwBuffer
|
||||
)
|
||||
{
|
||||
this->pushFromPortEntry_errorDeallocate(fwBuffer);
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Drv
|
||||
@ -1,99 +0,0 @@
|
||||
// ======================================================================
|
||||
// \title StreamCrossover/test/ut/Tester.hpp
|
||||
// \author ethanchee
|
||||
// \brief hpp file for StreamCrossover test harness implementation class
|
||||
// ======================================================================
|
||||
|
||||
#ifndef TESTER_HPP
|
||||
#define TESTER_HPP
|
||||
|
||||
#include "StreamCrossoverGTestBase.hpp"
|
||||
#include "Drv/StreamCrossover/StreamCrossover.hpp"
|
||||
|
||||
namespace Drv {
|
||||
|
||||
class StreamCrossoverTester :
|
||||
public StreamCrossoverGTestBase
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
// Maximum size of histories storing events, telemetry, and port outputs
|
||||
static const U32 MAX_HISTORY_SIZE = 10;
|
||||
// Instance ID supplied to the component instance under test
|
||||
static const FwEnumStoreType TEST_INSTANCE_ID = 0;
|
||||
|
||||
//! Construct object StreamCrossoverTester
|
||||
//!
|
||||
StreamCrossoverTester();
|
||||
|
||||
//! Destroy object StreamCrossoverTester
|
||||
//!
|
||||
~StreamCrossoverTester();
|
||||
|
||||
public:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Send a test buffer to streamOut from streamIn
|
||||
//!
|
||||
void sendTestBuffer();
|
||||
|
||||
//! Send a fail RECV_STATUS to test error
|
||||
//!
|
||||
void testFail();
|
||||
|
||||
private:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Handler for from_streamOut
|
||||
//!
|
||||
Drv::SendStatus from_streamOut_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &sendBuffer
|
||||
);
|
||||
|
||||
//! Handler for from_deallocate
|
||||
//!
|
||||
void from_errorDeallocate_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &fwBuffer
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Connect ports
|
||||
//!
|
||||
void connectPorts();
|
||||
|
||||
//! Initialize components
|
||||
//!
|
||||
void initComponents();
|
||||
|
||||
private:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Variables
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! The component under test
|
||||
//!
|
||||
StreamCrossover component;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Drv
|
||||
|
||||
#endif
|
||||
@ -3,9 +3,8 @@ module Drv {
|
||||
|
||||
include "../Interfaces/ByteStreamDriverInterface.fppi"
|
||||
|
||||
@ Allocation for received data
|
||||
output port allocate: Fw.BufferGet
|
||||
|
||||
output port deallocate: Fw.BufferSend
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,15 +52,15 @@ Fw::Buffer TcpClientComponentImpl::getBuffer() {
|
||||
}
|
||||
|
||||
void TcpClientComponentImpl::sendBuffer(Fw::Buffer buffer, SocketIpStatus status) {
|
||||
Drv::RecvStatus recvStatus = RecvStatus::RECV_ERROR;
|
||||
Drv::ByteStreamStatus recvStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
if (status == SOCK_SUCCESS) {
|
||||
recvStatus = RecvStatus::RECV_OK;
|
||||
recvStatus = ByteStreamStatus::OP_OK;
|
||||
}
|
||||
else if (status == SOCK_NO_DATA_AVAILABLE) {
|
||||
recvStatus = RecvStatus::RECV_NO_DATA;
|
||||
recvStatus = ByteStreamStatus::RECV_NO_DATA;
|
||||
}
|
||||
else {
|
||||
recvStatus = RecvStatus::RECV_ERROR;
|
||||
recvStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
}
|
||||
this->recv_out(0, buffer, recvStatus);
|
||||
}
|
||||
@ -76,17 +76,22 @@ void TcpClientComponentImpl::connected() {
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Drv::SendStatus TcpClientComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
void TcpClientComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
Drv::SocketIpStatus status = send(fwBuffer.getData(), fwBuffer.getSize());
|
||||
// Only deallocate buffer when the caller is not asked to retry
|
||||
if (status == SOCK_INTERRUPTED_TRY_AGAIN) {
|
||||
return SendStatus::SEND_RETRY;
|
||||
} else if (status != SOCK_SUCCESS) {
|
||||
deallocate_out(0, fwBuffer);
|
||||
return SendStatus::SEND_ERROR;
|
||||
Drv::ByteStreamStatus returnStatus;
|
||||
switch (status) {
|
||||
case SOCK_INTERRUPTED_TRY_AGAIN:
|
||||
returnStatus = ByteStreamStatus::SEND_RETRY;
|
||||
break;
|
||||
case SOCK_SUCCESS:
|
||||
returnStatus = ByteStreamStatus::OP_OK;
|
||||
break;
|
||||
default:
|
||||
returnStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
break;
|
||||
}
|
||||
deallocate_out(0, fwBuffer);
|
||||
return SendStatus::SEND_OK;
|
||||
// Return the buffer and status to the caller
|
||||
this->dataReturnOut_out(0, fwBuffer, returnStatus);
|
||||
}
|
||||
|
||||
} // end namespace Drv
|
||||
|
||||
@ -76,7 +76,7 @@ class TcpClientComponentImpl final : public TcpClientComponentBase, public Socke
|
||||
*
|
||||
* \return IpSocket reference
|
||||
*/
|
||||
IpSocket& getSocketHandler();
|
||||
IpSocket& getSocketHandler() override;
|
||||
|
||||
/**
|
||||
* \brief returns a buffer to fill with data
|
||||
@ -86,7 +86,7 @@ class TcpClientComponentImpl final : public TcpClientComponentBase, public Socke
|
||||
*
|
||||
* \return Fw::Buffer to fill with data
|
||||
*/
|
||||
Fw::Buffer getBuffer();
|
||||
Fw::Buffer getBuffer() override;
|
||||
|
||||
/**
|
||||
* \brief sends a buffer to be filled with data
|
||||
@ -96,12 +96,12 @@ class TcpClientComponentImpl final : public TcpClientComponentBase, public Socke
|
||||
*
|
||||
* \return Fw::Buffer filled with data to send out
|
||||
*/
|
||||
void sendBuffer(Fw::Buffer buffer, SocketIpStatus status);
|
||||
void sendBuffer(Fw::Buffer buffer, SocketIpStatus status) override;
|
||||
|
||||
/**
|
||||
* \brief called when the IPv4 system has been connected
|
||||
*/
|
||||
void connected();
|
||||
void connected() override;
|
||||
|
||||
|
||||
PRIVATE:
|
||||
@ -115,7 +115,7 @@ class TcpClientComponentImpl final : public TcpClientComponentBase, public Socke
|
||||
*
|
||||
* Passing data to this port will send data from the TcpClient to whatever TCP server this component has connected
|
||||
* to. Should the socket not be opened or was disconnected, then this port call will return SEND_RETRY and critical
|
||||
* transmissions should be retried. SEND_ERROR indicates an unresolvable error. SEND_OK is returned when the data
|
||||
* transmissions should be retried. OTHER_ERROR indicates an unresolvable error. OP_OK is returned when the data
|
||||
* has been sent.
|
||||
*
|
||||
* Note: this component delegates the reopening of the socket to the read thread and thus the caller should retry
|
||||
@ -123,9 +123,8 @@ class TcpClientComponentImpl final : public TcpClientComponentBase, public Socke
|
||||
*
|
||||
* \param portNum: fprime port number of the incoming port call
|
||||
* \param fwBuffer: buffer containing data to be sent
|
||||
* \return SEND_OK on success, SEND_RETRY when critical data should be retried and SEND_ERROR upon error
|
||||
*/
|
||||
Drv::SendStatus send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer);
|
||||
void send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) override;
|
||||
|
||||
Drv::TcpClientSocket m_socket; //!< Socket implementation
|
||||
|
||||
|
||||
@ -5,38 +5,14 @@ connects and sends/receives bytes. It implements the callback formation (shown b
|
||||
and producing the callback port call.
|
||||
|
||||
For more information on the supporting TCP implementation see: Drv::TcpClientSocket.
|
||||
For more information on the ByteStreamModelDriver see: Drv::ByteStreamDriverModel.
|
||||
For more information on the ByteStreamModelDriver see: [`Drv::ByteStreamDriverModel`](../../ByteStreamDriverModel/docs/sdd.md).
|
||||
|
||||
## Design
|
||||
|
||||
The manager component (typically the ground interface) initiates the transfer of send data by calling the "send" port.
|
||||
The caller will provide a `Fw::Buffer` containing the data to send and the port call will return a status of that send.
|
||||
These responses are an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| Drv::SEND_OK | Send functioned normally. |
|
||||
| Drv::SEND_RETRY | Send should be retried, but a subsequent send should return SEND_OK. |
|
||||
| Drv::SEND_ERROR | Send produced an error, future sends likely to fail. |
|
||||
|
||||
This data is immediately sent out to the remote tcp server with a configured send timeout. See Usage described below.
|
||||
|
||||
**Callback Formation**
|
||||
|
||||

|
||||
|
||||
In the callback formation, the byte stream driver component initiates the transfer of received data by calling the
|
||||
"readCallback" output port. This port transfers any read data in a `Fw::Buffer` along with a status for the receive.
|
||||
This status is an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| Drv::RECV_OK | Receive functioned normally buffer contains valid data. |
|
||||
| Drv::RECV_ERROR | Receive produced an error and buffer contains no valid data. |
|
||||
The TcpClient component implements the design specified by the [`Drv::ByteStreamDriverModel`](../../ByteStreamDriverModel/docs/sdd.md).
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
The Drv::TcpClientComponentImpl must be configured with the address of the remote connection using the `configure` method.
|
||||
The sockets must also be opened to send and receive data using `open`. When the component is set to automatically open,
|
||||
`open` is called via the first send or receive. Users declining to use automatic opening or who wish to control when open
|
||||
|
||||
@ -79,8 +79,10 @@ void TcpClientTester ::test_with_loop(U32 iterations, bool recv_thread) {
|
||||
Drv::Test::force_recv_timeout(server_fd.serverFd, server);
|
||||
m_data_buffer.setSize(sizeof(m_data_storage));
|
||||
size = Drv::Test::fill_random_buffer(m_data_buffer);
|
||||
Drv::SendStatus status = invoke_to_send(0, m_data_buffer);
|
||||
EXPECT_EQ(status, SendStatus::SEND_OK);
|
||||
invoke_to_send(0, m_data_buffer);
|
||||
ASSERT_from_dataReturnOut_SIZE(i + 1);
|
||||
Drv::ByteStreamStatus status = this->fromPortHistory_dataReturnOut->at(i).status;
|
||||
EXPECT_EQ(status, ByteStreamStatus::OP_OK);
|
||||
Drv::Test::receive_all(server, server_fd, buffer, size);
|
||||
Drv::Test::validate_random_buffer(m_data_buffer, buffer);
|
||||
// If receive thread is live, try the other way
|
||||
@ -89,7 +91,6 @@ void TcpClientTester ::test_with_loop(U32 iterations, bool recv_thread) {
|
||||
m_data_buffer.setSize(sizeof(m_data_storage));
|
||||
status2 = server.send(server_fd, m_data_buffer.getData(), m_data_buffer.getSize());
|
||||
EXPECT_EQ(status2, Drv::SOCK_SUCCESS);
|
||||
from_deallocate_handler(0, m_data_buffer);
|
||||
while (not m_spinner) {}
|
||||
}
|
||||
}
|
||||
@ -180,18 +181,18 @@ void TcpClientTester ::test_no_automatic_recv_connection() {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
// Handler overrides for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void TcpClientTester ::
|
||||
from_recv_handler(
|
||||
const FwIndexType portNum,
|
||||
Fw::Buffer &recvBuffer,
|
||||
const RecvStatus &recvStatus
|
||||
const ByteStreamStatus &ByteStreamStatus
|
||||
)
|
||||
{
|
||||
this->pushFromPortEntry_recv(recvBuffer, recvStatus);
|
||||
if (recvStatus == RecvStatus::RECV_OK){
|
||||
this->pushFromPortEntry_recv(recvBuffer, ByteStreamStatus);
|
||||
if (ByteStreamStatus == ByteStreamStatus::OP_OK){
|
||||
// Make sure we can get to unblocking the spinner
|
||||
EXPECT_EQ(m_data_buffer.getSize(), recvBuffer.getSize()) << "Invalid transmission size";
|
||||
Drv::Test::validate_random_buffer(m_data_buffer, recvBuffer.getData());
|
||||
@ -201,10 +202,6 @@ void TcpClientTester ::test_no_automatic_recv_connection() {
|
||||
delete[] recvBuffer.getData();
|
||||
}
|
||||
|
||||
void TcpClientTester ::from_ready_handler(const FwIndexType portNum) {
|
||||
this->pushFromPortEntry_ready();
|
||||
}
|
||||
|
||||
Fw::Buffer TcpClientTester ::
|
||||
from_allocate_handler(
|
||||
const FwIndexType portNum,
|
||||
@ -217,13 +214,4 @@ Fw::Buffer TcpClientTester ::
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void TcpClientTester ::
|
||||
from_deallocate_handler(
|
||||
const FwIndexType portNum,
|
||||
Fw::Buffer &fwBuffer
|
||||
)
|
||||
{
|
||||
this->pushFromPortEntry_deallocate(fwBuffer);
|
||||
}
|
||||
|
||||
} // end namespace Drv
|
||||
|
||||
@ -70,7 +70,7 @@ namespace Drv {
|
||||
private:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
// Handler overrides for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Handler for from_recv
|
||||
@ -78,28 +78,15 @@ namespace Drv {
|
||||
void from_recv_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &recvBuffer,
|
||||
const RecvStatus &recvStatus
|
||||
);
|
||||
|
||||
//! Handler for from_ready
|
||||
//!
|
||||
void from_ready_handler(
|
||||
const FwIndexType portNum /*!< The port number*/
|
||||
);
|
||||
const ByteStreamStatus &ByteStreamStatus
|
||||
) override;
|
||||
|
||||
//! Handler for from_allocate
|
||||
//!
|
||||
Fw::Buffer from_allocate_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
U32 size
|
||||
);
|
||||
|
||||
//! Handler for from_deallocate
|
||||
//!
|
||||
void from_deallocate_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &fwBuffer
|
||||
);
|
||||
) override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@ -3,9 +3,8 @@ module Drv {
|
||||
|
||||
include "../Interfaces/ByteStreamDriverInterface.fppi"
|
||||
|
||||
@ Allocation for received data
|
||||
output port allocate: Fw.BufferGet
|
||||
|
||||
output port deallocate: Fw.BufferSend
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,15 +59,15 @@ Fw::Buffer TcpServerComponentImpl::getBuffer() {
|
||||
}
|
||||
|
||||
void TcpServerComponentImpl::sendBuffer(Fw::Buffer buffer, SocketIpStatus status) {
|
||||
Drv::RecvStatus recvStatus = RecvStatus::RECV_ERROR;
|
||||
Drv::ByteStreamStatus recvStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
if (status == SOCK_SUCCESS) {
|
||||
recvStatus = RecvStatus::RECV_OK;
|
||||
recvStatus = ByteStreamStatus::OP_OK;
|
||||
}
|
||||
else if (status == SOCK_NO_DATA_AVAILABLE) {
|
||||
recvStatus = RecvStatus::RECV_NO_DATA;
|
||||
recvStatus = ByteStreamStatus::RECV_NO_DATA;
|
||||
}
|
||||
else {
|
||||
recvStatus = RecvStatus::RECV_ERROR;
|
||||
recvStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
}
|
||||
this->recv_out(0, buffer, recvStatus);
|
||||
}
|
||||
@ -124,17 +124,22 @@ void TcpServerComponentImpl::readLoop() {
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Drv::SendStatus TcpServerComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
void TcpServerComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
Drv::SocketIpStatus status = this->send(fwBuffer.getData(), fwBuffer.getSize());
|
||||
// Only deallocate buffer when the caller is not asked to retry
|
||||
if (status == SOCK_INTERRUPTED_TRY_AGAIN) {
|
||||
return SendStatus::SEND_RETRY;
|
||||
} else if (status != SOCK_SUCCESS) {
|
||||
deallocate_out(0, fwBuffer);
|
||||
return SendStatus::SEND_ERROR;
|
||||
Drv::ByteStreamStatus returnStatus;
|
||||
switch (status) {
|
||||
case SOCK_INTERRUPTED_TRY_AGAIN:
|
||||
returnStatus = ByteStreamStatus::SEND_RETRY;
|
||||
break;
|
||||
case SOCK_SUCCESS:
|
||||
returnStatus = ByteStreamStatus::OP_OK;
|
||||
break;
|
||||
default:
|
||||
returnStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
break;
|
||||
}
|
||||
deallocate_out(0, fwBuffer);
|
||||
return SendStatus::SEND_OK;
|
||||
// Return the buffer and status to the caller
|
||||
this->dataReturnOut_out(0, fwBuffer, returnStatus);
|
||||
}
|
||||
|
||||
} // end namespace Drv
|
||||
|
||||
@ -150,7 +150,7 @@ class TcpServerComponentImpl final : public TcpServerComponentBase, public Socke
|
||||
*
|
||||
* Passing data to this port will send data from the TcpServer to whatever TCP client this component has connected
|
||||
* to. Should the socket not be opened or was disconnected, then this port call will return SEND_RETRY and critical
|
||||
* transmissions should be retried. SEND_ERROR indicates an unresolvable error. SEND_OK is returned when the data
|
||||
* transmissions should be retried. OTHER_ERROR indicates an unresolvable error. OP_OK is returned when the data
|
||||
* has been sent.
|
||||
*
|
||||
* Note: this component delegates the reopening of the socket to the read thread and thus the caller should retry
|
||||
@ -158,9 +158,8 @@ class TcpServerComponentImpl final : public TcpServerComponentBase, public Socke
|
||||
*
|
||||
* \param portNum: fprime port number of the incoming port call
|
||||
* \param fwBuffer: buffer containing data to be sent
|
||||
* \return SEND_OK on success, SEND_RETRY when critical data should be retried and SEND_ERROR upon error
|
||||
*/
|
||||
Drv::SendStatus send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) override;
|
||||
void send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) override;
|
||||
|
||||
Drv::TcpServerSocket m_socket; //!< Socket implementation
|
||||
|
||||
|
||||
@ -6,34 +6,11 @@ and producing the callback port call. Since it is a server, it must startup and
|
||||
for single client communication, it does not permit a queue of connecting clients.
|
||||
|
||||
For more information on the supporting TCP implementation see: [Drv::TcpServerSocket](../../Ip/docs/sdd.md#drvtcpserversocket-class).
|
||||
For more information on the ByteStreamModelDriver see: [Drv::ByteStreamDriverModel](../..//ByteStreamDriverModel/docs/sdd.md).
|
||||
For more information on the ByteStreamModelDriver see: [Drv::ByteStreamDriverModel](../../ByteStreamDriverModel/docs/sdd.md).
|
||||
|
||||
## Design
|
||||
|
||||
The manager component (typically the ground interface) initiates the transfer of send data by calling the "send" port.
|
||||
The caller will provide a `Fw::Buffer` containing the data to send and the port call will return a status of that send.
|
||||
These responses are an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| Drv::SEND_OK | Send functioned normally. |
|
||||
| Drv::SEND_RETRY | Send should be retried, but a subsequent send should return SEND_OK. |
|
||||
| Drv::SEND_ERROR | Send produced an error, future sends likely to fail. |
|
||||
|
||||
This data is immediately sent out to the remote tcp server with a configured send timeout. See Usage described below.
|
||||
|
||||
**Callback Formation**
|
||||
|
||||

|
||||
|
||||
In the callback formation, the byte stream driver component initiates the transfer of received data by calling the
|
||||
"readCallback" output port. This port transfers any read data in a `Fw::Buffer` along with a status for the receive.
|
||||
This status is an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| Drv::RECV_OK | Receive functioned normally buffer contains valid data. |
|
||||
| Drv::RECV_ERROR | Receive produced an error and buffer contains no valid data. |
|
||||
The TcpClient component implements the design specified by the [`Drv::ByteStreamDriverModel`](../../ByteStreamDriverModel/docs/sdd.md).
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@ -80,8 +80,10 @@ void TcpServerTester ::test_with_loop(U32 iterations, bool recv_thread) {
|
||||
Drv::Test::force_recv_timeout(client_fd.fd, client);
|
||||
m_data_buffer.setSize(sizeof(m_data_storage));
|
||||
size = Drv::Test::fill_random_buffer(m_data_buffer);
|
||||
Drv::SendStatus status = invoke_to_send(0, m_data_buffer);
|
||||
EXPECT_EQ(status, SendStatus::SEND_OK) <<
|
||||
invoke_to_send(0, m_data_buffer);
|
||||
ASSERT_from_dataReturnOut_SIZE(i + 1);
|
||||
Drv::ByteStreamStatus status = this->fromPortHistory_dataReturnOut->at(i).status;
|
||||
EXPECT_EQ(status, ByteStreamStatus::OP_OK) <<
|
||||
"On iteration: " << i << " and receive thread: " << recv_thread;
|
||||
Drv::Test::receive_all(client, client_fd, buffer, size);
|
||||
EXPECT_EQ(status2, Drv::SOCK_SUCCESS) <<
|
||||
@ -219,10 +221,10 @@ void TcpServerTester ::test_no_automatic_recv_connection() {
|
||||
// Handlers for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void TcpServerTester ::from_recv_handler(const FwIndexType portNum, Fw::Buffer& recvBuffer, const RecvStatus& recvStatus) {
|
||||
void TcpServerTester ::from_recv_handler(const FwIndexType portNum, Fw::Buffer& recvBuffer, const ByteStreamStatus& recvStatus) {
|
||||
// this function will still receive a status of error because the recv port is always called
|
||||
this->pushFromPortEntry_recv(recvBuffer, recvStatus);
|
||||
if (recvStatus == RecvStatus::RECV_OK) {
|
||||
if (recvStatus == ByteStreamStatus::OP_OK) {
|
||||
// Make sure we can get to unblocking the spinner
|
||||
EXPECT_EQ(m_data_buffer.getSize(), recvBuffer.getSize()) << "Invalid transmission size";
|
||||
Drv::Test::validate_random_buffer(m_data_buffer, recvBuffer.getData());
|
||||
@ -231,10 +233,6 @@ void TcpServerTester ::from_recv_handler(const FwIndexType portNum, Fw::Buffer&
|
||||
delete[] recvBuffer.getData();
|
||||
}
|
||||
|
||||
void TcpServerTester ::from_ready_handler(const FwIndexType portNum) {
|
||||
this->pushFromPortEntry_ready();
|
||||
}
|
||||
|
||||
Fw::Buffer TcpServerTester ::
|
||||
from_allocate_handler(
|
||||
const FwIndexType portNum,
|
||||
@ -246,12 +244,4 @@ Fw::Buffer TcpServerTester ::
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void TcpServerTester ::
|
||||
from_deallocate_handler(
|
||||
const FwIndexType portNum,
|
||||
Fw::Buffer &fwBuffer
|
||||
)
|
||||
{
|
||||
this->pushFromPortEntry_deallocate(fwBuffer);
|
||||
}
|
||||
} // end namespace Drv
|
||||
|
||||
@ -82,7 +82,7 @@ namespace Drv {
|
||||
private:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
// Handlers overrides for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Handler for from_recv
|
||||
@ -90,28 +90,15 @@ namespace Drv {
|
||||
void from_recv_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &recvBuffer,
|
||||
const RecvStatus &recvStatus
|
||||
);
|
||||
|
||||
//! Handler for from_ready
|
||||
//!
|
||||
void from_ready_handler(
|
||||
const FwIndexType portNum /*!< The port number*/
|
||||
);
|
||||
const ByteStreamStatus &recvStatus
|
||||
) override;
|
||||
|
||||
//! Handler for from_allocate
|
||||
//!
|
||||
Fw::Buffer from_allocate_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
U32 size
|
||||
);
|
||||
|
||||
//! Handler for from_deallocate
|
||||
//!
|
||||
void from_deallocate_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &fwBuffer
|
||||
);
|
||||
) override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@ -5,7 +5,5 @@ module Drv {
|
||||
|
||||
output port allocate: Fw.BufferGet
|
||||
|
||||
output port deallocate: Fw.BufferSend
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,15 +59,15 @@ Fw::Buffer UdpComponentImpl::getBuffer() {
|
||||
}
|
||||
|
||||
void UdpComponentImpl::sendBuffer(Fw::Buffer buffer, SocketIpStatus status) {
|
||||
Drv::RecvStatus recvStatus = RecvStatus::RECV_ERROR;
|
||||
Drv::ByteStreamStatus recvStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
if (status == SOCK_SUCCESS) {
|
||||
recvStatus = RecvStatus::RECV_OK;
|
||||
recvStatus = ByteStreamStatus::OP_OK;
|
||||
}
|
||||
else if (status == SOCK_NO_DATA_AVAILABLE) {
|
||||
recvStatus = RecvStatus::RECV_NO_DATA;
|
||||
recvStatus = ByteStreamStatus::RECV_NO_DATA;
|
||||
}
|
||||
else {
|
||||
recvStatus = RecvStatus::RECV_ERROR;
|
||||
recvStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
}
|
||||
this->recv_out(0, buffer, recvStatus);
|
||||
}
|
||||
@ -82,16 +82,25 @@ void UdpComponentImpl::connected() {
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Drv::SendStatus UdpComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
void UdpComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
Drv::SocketIpStatus status = send(fwBuffer.getData(), fwBuffer.getSize());
|
||||
// Always return the buffer
|
||||
deallocate_out(0, fwBuffer);
|
||||
if ((status == SOCK_DISCONNECTED) || (status == SOCK_INTERRUPTED_TRY_AGAIN)) {
|
||||
return SendStatus::SEND_RETRY;
|
||||
} else if (status != SOCK_SUCCESS) {
|
||||
return SendStatus::SEND_ERROR;
|
||||
Drv::ByteStreamStatus returnStatus;
|
||||
switch (status) {
|
||||
case SOCK_INTERRUPTED_TRY_AGAIN:
|
||||
returnStatus = ByteStreamStatus::SEND_RETRY;
|
||||
break;
|
||||
case SOCK_DISCONNECTED:
|
||||
returnStatus = ByteStreamStatus::SEND_RETRY;
|
||||
break;
|
||||
case SOCK_SUCCESS:
|
||||
returnStatus = ByteStreamStatus::OP_OK;
|
||||
break;
|
||||
default:
|
||||
returnStatus = ByteStreamStatus::OTHER_ERROR;
|
||||
break;
|
||||
}
|
||||
return SendStatus::SEND_OK;
|
||||
// Return the buffer and status to the caller
|
||||
this->dataReturnOut_out(0, fwBuffer, returnStatus);
|
||||
}
|
||||
|
||||
} // end namespace Drv
|
||||
|
||||
@ -137,7 +137,7 @@ PROTECTED:
|
||||
*
|
||||
* Passing data to this port will send data from the TcpClient to whatever TCP server this component has connected
|
||||
* to. Should the socket not be opened or was disconnected, then this port call will return SEND_RETRY and critical
|
||||
* transmissions should be retried. SEND_ERROR indicates an unresolvable error. SEND_OK is returned when the data
|
||||
* transmissions should be retried. OTHER_ERROR indicates an unresolvable error. OP_OK is returned when the data
|
||||
* has been sent.
|
||||
*
|
||||
* Note: this component delegates the reopening of the socket to the read thread and thus the caller should retry
|
||||
@ -145,9 +145,8 @@ PROTECTED:
|
||||
*
|
||||
* \param portNum: fprime port number of the incoming port call
|
||||
* \param fwBuffer: buffer containing data to be sent
|
||||
* \return SEND_OK on success, SEND_RETRY when critical data should be retried and SEND_ERROR upon error
|
||||
*/
|
||||
Drv::SendStatus send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer);
|
||||
void send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer);
|
||||
|
||||
Drv::UdpSocket m_socket; //!< Socket implementation
|
||||
|
||||
|
||||
@ -9,30 +9,7 @@ For more information on the ByteStreamModelDriver see: Drv::ByteStreamDriverMode
|
||||
|
||||
## Design
|
||||
|
||||
The manager component (typically the ground interface) initiates the transfer of send data by calling the "send" port.
|
||||
The caller will provide a `Fw::Buffer` containing the data to send and the port call will return a status of that send.
|
||||
These responses are an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| Drv::SEND_OK | Send functioned normally. |
|
||||
| Drv::SEND_RETRY | Send should be retried, but a subsequent send should return SEND_OK. |
|
||||
| Drv::SEND_ERROR | Send produced an error, future sends likely to fail. |
|
||||
|
||||
This data is immediately sent out to the remote UDP server with a configured send timeout. See Usage described below.
|
||||
|
||||
**Callback Formation**
|
||||
|
||||

|
||||
|
||||
In the callback formation, the byte stream driver component initiates the transfer of received data by calling the
|
||||
"readCallback" output port. This port transfers any read data in a `Fw::Buffer` along with a status for the receive.
|
||||
This status is an enumeration whose values are described in the following table:
|
||||
|
||||
| Value | Description |
|
||||
|---|---|
|
||||
| Drv::RECV_OK | Receive functioned normally buffer contains valid data. |
|
||||
| Drv::RECV_ERROR | Receive produced an error and buffer contains no valid data. |
|
||||
The TcpClient component implements the design specified by the [`Drv::ByteStreamDriverModel`](../../ByteStreamDriverModel/docs/sdd.md).
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@ -91,8 +91,10 @@ void UdpTester::test_with_loop(U32 iterations, bool recv_thread) {
|
||||
Drv::Test::force_recv_timeout(udp2_fd.fd, udp2);
|
||||
m_data_buffer.setSize(sizeof(m_data_storage));
|
||||
size = Drv::Test::fill_random_buffer(m_data_buffer);
|
||||
Drv::SendStatus status = invoke_to_send(0, m_data_buffer);
|
||||
EXPECT_EQ(status, SendStatus::SEND_OK);
|
||||
invoke_to_send(0, m_data_buffer);
|
||||
ASSERT_from_dataReturnOut_SIZE(i + 1);
|
||||
Drv::ByteStreamStatus status = this->fromPortHistory_dataReturnOut->at(i).status;
|
||||
EXPECT_EQ(status, ByteStreamStatus::OP_OK);
|
||||
Drv::Test::receive_all(udp2, udp2_fd, buffer, size);
|
||||
Drv::Test::validate_random_buffer(m_data_buffer, buffer);
|
||||
// If receive thread is live, try the other way
|
||||
@ -160,10 +162,10 @@ void UdpTester ::test_advanced_reconnect() {
|
||||
// Handlers for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void UdpTester ::from_recv_handler(const FwIndexType portNum, Fw::Buffer& recvBuffer, const RecvStatus& recvStatus) {
|
||||
void UdpTester ::from_recv_handler(const FwIndexType portNum, Fw::Buffer& recvBuffer, const ByteStreamStatus& recvStatus) {
|
||||
this->pushFromPortEntry_recv(recvBuffer, recvStatus);
|
||||
// Make sure we can get to unblocking the spinner
|
||||
if (recvStatus == RecvStatus::RECV_OK){
|
||||
if (recvStatus == ByteStreamStatus::OP_OK){
|
||||
EXPECT_EQ(m_data_buffer.getSize(), recvBuffer.getSize()) << "Invalid transmission size";
|
||||
Drv::Test::validate_random_buffer(m_data_buffer, recvBuffer.getData());
|
||||
m_spinner = true;
|
||||
@ -171,10 +173,6 @@ void UdpTester ::from_recv_handler(const FwIndexType portNum, Fw::Buffer& recvBu
|
||||
delete[] recvBuffer.getData();
|
||||
}
|
||||
|
||||
void UdpTester ::from_ready_handler(const FwIndexType portNum) {
|
||||
this->pushFromPortEntry_ready();
|
||||
}
|
||||
|
||||
Fw::Buffer UdpTester ::
|
||||
from_allocate_handler(
|
||||
const FwIndexType portNum,
|
||||
@ -187,13 +185,4 @@ Fw::Buffer UdpTester ::
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void UdpTester ::
|
||||
from_deallocate_handler(
|
||||
const FwIndexType portNum,
|
||||
Fw::Buffer &fwBuffer
|
||||
)
|
||||
{
|
||||
this->pushFromPortEntry_deallocate(fwBuffer);
|
||||
}
|
||||
|
||||
} // end namespace Drv
|
||||
|
||||
@ -77,7 +77,7 @@ namespace Drv {
|
||||
private:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
// Handler overrides for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Handler for from_recv
|
||||
@ -85,28 +85,15 @@ namespace Drv {
|
||||
void from_recv_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &recvBuffer,
|
||||
const RecvStatus &recvStatus
|
||||
);
|
||||
|
||||
//! Handler for from_ready
|
||||
//!
|
||||
void from_ready_handler(
|
||||
const FwIndexType portNum /*!< The port number*/
|
||||
);
|
||||
const ByteStreamStatus &recvStatus
|
||||
) override;
|
||||
|
||||
//! Handler for from_allocate
|
||||
//!
|
||||
Fw::Buffer from_allocate_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
U32 size
|
||||
);
|
||||
|
||||
//! Handler for from_deallocate
|
||||
//!
|
||||
void from_deallocate_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &fwBuffer
|
||||
);
|
||||
) override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@ -16,8 +16,4 @@ module Fw {
|
||||
$size: U32
|
||||
) -> Fw.Buffer
|
||||
|
||||
|
||||
@ Port for sending data buffer along with context buffer
|
||||
@ This is useful for passing data that needs context to be interpreted
|
||||
port DataWithContext(ref data: Fw.Buffer, ref context: Fw.Buffer)
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ module RPI {
|
||||
async input port Run: Svc.Sched
|
||||
|
||||
@ Input port for receiving UART data
|
||||
async input port UartRead: Drv.ByteStreamRecv
|
||||
async input port UartRead: Drv.ByteStreamData
|
||||
|
||||
@ Output Port for reading GPIO values
|
||||
output port GpioRead: [2] Drv.GpioRead
|
||||
@ -42,7 +42,10 @@ module RPI {
|
||||
output port GpioWrite: [3] Drv.GpioWrite
|
||||
|
||||
@ Output Port for writing UART data
|
||||
output port UartWrite: Drv.ByteStreamSend
|
||||
output port UartWrite: Fw.BufferSend
|
||||
|
||||
@ Input port for getting back buffer ownership and status when using UartWrite
|
||||
sync input port UartWriteReturn: Drv.ByteStreamData
|
||||
|
||||
@ Output port for sending UART buffers to use for reading
|
||||
output port UartBuffers: Fw.BufferSend
|
||||
|
||||
@ -106,10 +106,10 @@ namespace RPI {
|
||||
UartRead_handler(
|
||||
const FwIndexType portNum,
|
||||
Fw::Buffer &serBuffer,
|
||||
const Drv::RecvStatus &status
|
||||
const Drv::ByteStreamStatus &status
|
||||
)
|
||||
{
|
||||
if (Drv::RecvStatus::RECV_OK == status.e) {
|
||||
if (Drv::ByteStreamStatus::OP_OK == status.e) {
|
||||
// convert incoming data to string. If it is not printable, set character to '*'
|
||||
char uMsg[serBuffer.getSize() + 1];
|
||||
char *bPtr = reinterpret_cast<char *>(serBuffer.getData());
|
||||
@ -142,16 +142,18 @@ namespace RPI {
|
||||
Fw::Buffer txt;
|
||||
txt.setSize(text.length());
|
||||
txt.setData(reinterpret_cast<U8*>(const_cast<char*>(text.toChar())));
|
||||
Drv::SendStatus status = this->UartWrite_out(0, txt);
|
||||
if (Drv::SendStatus::SEND_OK == status.e) {
|
||||
this->m_uartWriteBytes += text.length();
|
||||
|
||||
Fw::LogStringArg arg = text;
|
||||
this->log_ACTIVITY_HI_RD_UartMsgOut(arg);
|
||||
}
|
||||
this->UartWrite_out(0, txt);
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
|
||||
}
|
||||
|
||||
void RpiDemoComponentImpl ::UartWriteReturn_handler(FwIndexType portNum, Fw::Buffer& buffer, const Drv::ByteStreamStatus& status) {
|
||||
if (Drv::ByteStreamStatus::OP_OK == status.e) {
|
||||
this->m_uartWriteBytes += buffer.getSize();
|
||||
Fw::LogStringArg arg(reinterpret_cast<char *>(buffer.getData()));
|
||||
this->log_ACTIVITY_HI_RD_UartMsgOut(arg);
|
||||
}
|
||||
}
|
||||
|
||||
void RpiDemoComponentImpl ::
|
||||
RD_SetGpio_cmdHandler(
|
||||
const FwOpcodeType opCode,
|
||||
|
||||
@ -68,9 +68,16 @@ namespace RPI {
|
||||
void UartRead_handler(
|
||||
const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer &serBuffer, /*!< Buffer containing data*/
|
||||
const Drv::RecvStatus &status /*!< Status of read*/
|
||||
const Drv::ByteStreamStatus &status /*!< Status of read*/
|
||||
) override;
|
||||
|
||||
//! Handler implementation for UartWriteReturn
|
||||
//!
|
||||
//! Input port for getting back buffer ownership and status when using UartWrite
|
||||
void UartWriteReturn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& buffer,
|
||||
const Drv::ByteStreamStatus& status) override;
|
||||
|
||||
PRIVATE:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include "Fw/Types/MallocAllocator.hpp"
|
||||
#include "Os/Console.hpp"
|
||||
#include "RPI/Top/FppConstantsAc.hpp"
|
||||
#include "Svc/FramingProtocol/FprimeProtocol.hpp"
|
||||
#include "Svc/LinuxTimer/LinuxTimer.hpp"
|
||||
#include <Svc/FrameAccumulator/FrameDetector/FprimeFrameDetector.hpp>
|
||||
|
||||
|
||||
@ -148,6 +148,30 @@ module RPI {
|
||||
stack size Default.stackSize \
|
||||
priority 30
|
||||
|
||||
instance comQueue: Svc.ComQueue base id 0x1100 \
|
||||
queue size 50 \
|
||||
stack size Default.stackSize \
|
||||
priority 100 \
|
||||
{
|
||||
phase Fpp.ToCpp.Phases.configObjects """
|
||||
Svc::ComQueue::QueueConfigurationTable configurationTable;
|
||||
"""
|
||||
phase Fpp.ToCpp.Phases.configComponents """
|
||||
// Events (highest-priority)
|
||||
ConfigObjects::RPI_comQueue::configurationTable.entries[0].depth = 100;
|
||||
ConfigObjects::RPI_comQueue::configurationTable.entries[0].priority = 0;
|
||||
// Telemetry
|
||||
ConfigObjects::RPI_comQueue::configurationTable.entries[1].depth = 500;
|
||||
ConfigObjects::RPI_comQueue::configurationTable.entries[1].priority = 2;
|
||||
// File Downlink
|
||||
ConfigObjects::RPI_comQueue::configurationTable.entries[2].depth = 100;
|
||||
ConfigObjects::RPI_comQueue::configurationTable.entries[2].priority = 1;
|
||||
|
||||
RPI::comQueue.configure(ConfigObjects::RPI_comQueue::configurationTable, 0, Allocation::mallocator);
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Queued component instances
|
||||
# ----------------------------------------------------------------------
|
||||
@ -214,22 +238,11 @@ module RPI {
|
||||
|
||||
instance fatalAdapter: Svc.AssertFatalAdapter base id 1000
|
||||
|
||||
instance downlink: Svc.Framer base id 1220 \
|
||||
{
|
||||
|
||||
phase Fpp.ToCpp.Phases.configObjects """
|
||||
Svc::FprimeFraming framing;
|
||||
"""
|
||||
|
||||
phase Fpp.ToCpp.Phases.configComponents """
|
||||
RPI::downlink.setup(ConfigObjects::RPI_downlink::framing);
|
||||
"""
|
||||
|
||||
}
|
||||
instance framer: Svc.FprimeFramer base id 1220
|
||||
|
||||
instance deframer: Svc.FprimeDeframer base id 1240
|
||||
|
||||
instance comm: Drv.TcpClient base id 1260 \
|
||||
instance comDriver: Drv.TcpClient base id 1260 \
|
||||
{
|
||||
|
||||
phase Fpp.ToCpp.Phases.configConstants """
|
||||
@ -242,7 +255,7 @@ module RPI {
|
||||
phase Fpp.ToCpp.Phases.configComponents """
|
||||
// Configure socket server if and only if there is a valid specification
|
||||
if (state.hostName != nullptr && state.portNumber != 0) {
|
||||
RPI::comm.configure(state.hostName, state.portNumber);
|
||||
RPI::comDriver.configure(state.hostName, state.portNumber);
|
||||
}
|
||||
"""
|
||||
|
||||
@ -251,20 +264,20 @@ module RPI {
|
||||
if (state.hostName != nullptr && state.portNumber != 0) {
|
||||
// Uplink is configured for receive so a socket task is started
|
||||
Os::TaskString name("ReceiveTask");
|
||||
RPI::comm.start(
|
||||
RPI::comDriver.start(
|
||||
name,
|
||||
ConfigConstants::RPI_comm::PRIORITY,
|
||||
ConfigConstants::RPI_comm::STACK_SIZE
|
||||
ConfigConstants::RPI_comDriver::PRIORITY,
|
||||
ConfigConstants::RPI_comDriver::STACK_SIZE
|
||||
);
|
||||
}
|
||||
"""
|
||||
|
||||
phase Fpp.ToCpp.Phases.stopTasks """
|
||||
RPI::comm.stop();
|
||||
RPI::comDriver.stop();
|
||||
"""
|
||||
|
||||
phase Fpp.ToCpp.Phases.freeThreads """
|
||||
(void) RPI::comm.join();
|
||||
(void) RPI::comDriver.join();
|
||||
"""
|
||||
|
||||
}
|
||||
@ -474,4 +487,7 @@ module RPI {
|
||||
|
||||
instance fprimeRouter: Svc.FprimeRouter base id 3000
|
||||
|
||||
instance comStub: Svc.ComStub base id 3100
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -10,9 +10,11 @@ module RPI {
|
||||
instance chanTlm
|
||||
instance cmdDisp
|
||||
instance cmdSeq
|
||||
instance comm
|
||||
instance comQueue
|
||||
instance comDriver
|
||||
instance comStub
|
||||
instance deframer
|
||||
instance downlink
|
||||
instance framer
|
||||
instance eventLogger
|
||||
instance fatalAdapter
|
||||
instance fatalHandler
|
||||
@ -61,11 +63,26 @@ module RPI {
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
connections Downlink {
|
||||
chanTlm.PktSend -> downlink.comIn
|
||||
downlink.bufferDeallocate -> fileDownlink.bufferReturn
|
||||
downlink.framedOut -> comm.$send
|
||||
eventLogger.PktSend -> downlink.comIn
|
||||
fileDownlink.bufferSendOut -> downlink.bufferIn
|
||||
eventLogger.PktSend -> comQueue.comPacketQueueIn[0]
|
||||
chanTlm.PktSend -> comQueue.comPacketQueueIn[1]
|
||||
fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[0]
|
||||
|
||||
comQueue.queueSend -> framer.dataIn
|
||||
comQueue.bufferReturnOut[0] -> fileDownlink.bufferReturn
|
||||
framer.dataReturnOut -> comQueue.bufferReturnIn
|
||||
|
||||
framer.bufferAllocate -> commsBufferManager.bufferGetCallee
|
||||
framer.bufferDeallocate -> commsBufferManager.bufferSendIn
|
||||
|
||||
framer.dataOut -> comStub.comDataIn
|
||||
comStub.dataReturnOut -> framer.dataReturnIn
|
||||
comDriver.dataReturnOut -> comStub.dataReturnIn
|
||||
|
||||
comDriver.ready -> comStub.drvConnected
|
||||
comStub.drvDataOut -> comDriver.$send
|
||||
|
||||
comStub.comStatusOut -> framer.comStatusIn
|
||||
framer.comStatusOut -> comQueue.comStatusIn
|
||||
}
|
||||
|
||||
connections FaultProtection {
|
||||
@ -109,9 +126,7 @@ module RPI {
|
||||
}
|
||||
|
||||
connections MemoryAllocations {
|
||||
comm.allocate -> commsBufferManager.bufferGetCallee
|
||||
comm.deallocate -> commsBufferManager.bufferSendIn
|
||||
downlink.framedAllocate -> commsBufferManager.bufferGetCallee
|
||||
comDriver.allocate -> commsBufferManager.bufferGetCallee
|
||||
fileUplink.bufferSendOut -> commsBufferManager.bufferSendIn
|
||||
frameAccumulator.bufferAllocate -> commsBufferManager.bufferGetCallee
|
||||
frameAccumulator.bufferDeallocate -> commsBufferManager.bufferSendIn
|
||||
@ -124,10 +139,12 @@ module RPI {
|
||||
rpiDemo.UartWrite -> uartDrv.$send
|
||||
uartDrv.$recv -> rpiDemo.UartRead
|
||||
uartDrv.allocate -> uartBufferManager.bufferGetCallee
|
||||
uartDrv.dataReturnOut -> rpiDemo.UartWriteReturn
|
||||
}
|
||||
|
||||
connections Uplink {
|
||||
comm.$recv -> frameAccumulator.dataIn
|
||||
comDriver.$recv -> comStub.drvDataIn
|
||||
comStub.comDataOut -> frameAccumulator.dataIn
|
||||
|
||||
frameAccumulator.frameOut -> deframer.framedIn
|
||||
deframer.deframedOut -> fprimeRouter.dataIn
|
||||
|
||||
@ -15,10 +15,6 @@ set(SOURCE_FILES
|
||||
set(MOD_DEPS
|
||||
Fw/Logger
|
||||
Svc/PosixTime
|
||||
# Communication Implementations
|
||||
Drv/Udp
|
||||
Drv/TcpClient
|
||||
Drv/TcpServer
|
||||
)
|
||||
|
||||
register_fprime_module()
|
||||
|
||||
@ -17,6 +17,8 @@ telemetry packets RefPackets {
|
||||
Ref.fileDownlink.FilesSent
|
||||
Ref.fileDownlink.PacketsSent
|
||||
Ref.fileManager.CommandsExecuted
|
||||
Ref.comQueue.comQueueDepth
|
||||
Ref.comQueue.buffQueueDepth
|
||||
# Ref.tlmSend.SendLevel
|
||||
}
|
||||
|
||||
|
||||
@ -14,8 +14,8 @@
|
||||
// Necessary project-specified types
|
||||
#include <Fw/Types/MallocAllocator.hpp>
|
||||
#include <Os/Console.hpp>
|
||||
#include <Svc/FramingProtocol/FprimeProtocol.hpp>
|
||||
#include <Svc/FrameAccumulator/FrameDetector/FprimeFrameDetector.hpp>
|
||||
#include <Ref/Top/Ports_ComPacketQueueEnumAc.hpp>
|
||||
|
||||
// Used for 1Hz synthetic cycling
|
||||
#include <Os/Mutex.hpp>
|
||||
@ -32,7 +32,6 @@ Fw::MallocAllocator mallocator;
|
||||
|
||||
// The reference topology uses the F´ packet protocol when communicating with the ground and therefore uses the F´
|
||||
// framing and deframing implementations.
|
||||
Svc::FprimeFraming framing;
|
||||
Svc::FrameDetectors::FprimeFrameDetector frameDetector;
|
||||
|
||||
|
||||
@ -46,6 +45,8 @@ U32 rateGroup1Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
|
||||
U32 rateGroup2Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
|
||||
U32 rateGroup3Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {};
|
||||
|
||||
Svc::ComQueue::QueueConfigurationTable configurationTable;
|
||||
|
||||
// A number of constants are needed for construction of the topology. These are specified here.
|
||||
enum TopologyConstants {
|
||||
CMD_SEQ_BUFFER_SIZE = 5 * 1024,
|
||||
@ -113,8 +114,6 @@ void configureTopology() {
|
||||
dpBuffMgrBins.bins[0].numBuffers = DP_BUFFER_MANAGER_STORE_COUNT;
|
||||
dpBufferManager.setup(DP_BUFFER_MANAGER_ID, 0, mallocator, dpBuffMgrBins);
|
||||
|
||||
// Framer and Deframer components need to be passed a protocol handler
|
||||
framer.setup(framing);
|
||||
frameAccumulator.configure(frameDetector, 1, mallocator, 2048);
|
||||
|
||||
Fw::FileNameString dpDir("./DpCat");
|
||||
@ -126,6 +125,19 @@ void configureTopology() {
|
||||
dpCat.configure(&dpDir,1,dpState,0,mallocator);
|
||||
dpWriter.configure(dpDir);
|
||||
|
||||
// ComQueue configuration
|
||||
// Events (highest-priority)
|
||||
configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].depth = 100;
|
||||
configurationTable.entries[Ref::Ports_ComPacketQueue::EVENTS].priority = 0;
|
||||
// Telemetry
|
||||
configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].depth = 500;
|
||||
configurationTable.entries[Ref::Ports_ComPacketQueue::TELEMETRY].priority = 2;
|
||||
// File Downlink (first entry after the ComPacket queues = NUM_CONSTANTS)
|
||||
configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].depth = 100;
|
||||
configurationTable.entries[Ref::Ports_ComPacketQueue::NUM_CONSTANTS].priority = 1;
|
||||
// Allocation identifier is 0 as the MallocAllocator discards it
|
||||
comQueue.configure(configurationTable, 0, mallocator);
|
||||
|
||||
// Note: Uncomment when using Svc:TlmPacketizer
|
||||
// tlmSend.setPacketList(Ref::Ref_RefPacketsTlmPackets::packetList, Ref::Ref_RefPacketsTlmPackets::omittedChannels, 1);
|
||||
}
|
||||
@ -144,7 +156,7 @@ void setupTopology(const TopologyState& state) {
|
||||
// Autocoded configuration. Function provided by autocoder.
|
||||
configComponents(state);
|
||||
if (state.hostname != nullptr && state.port != 0) {
|
||||
comm.configure(state.hostname, state.port);
|
||||
comDriver.configure(state.hostname, state.port);
|
||||
}
|
||||
// Project-specific component configuration. Function provided above. May be inlined, if desired.
|
||||
configureTopology();
|
||||
@ -158,7 +170,7 @@ void setupTopology(const TopologyState& state) {
|
||||
if (state.hostname != nullptr && state.port != 0) {
|
||||
Os::TaskString name("ReceiveTask");
|
||||
// Uplink is configured for receive so a socket task is started
|
||||
comm.start(name, COMM_PRIORITY, Default::STACK_SIZE);
|
||||
comDriver.start(name, COMM_PRIORITY, Default::STACK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,8 +206,8 @@ void teardownTopology(const TopologyState& state) {
|
||||
freeThreads(state);
|
||||
|
||||
// Other task clean-up.
|
||||
comm.stop();
|
||||
(void)comm.join();
|
||||
comDriver.stop();
|
||||
(void)comDriver.join();
|
||||
|
||||
// Resource deallocation
|
||||
cmdSeq.deallocateBuffer(mallocator);
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
#include "Drv/BlockDriver/BlockDriver.hpp"
|
||||
#include "Fw/Types/MallocAllocator.hpp"
|
||||
#include "Ref/Top/FppConstantsAc.hpp"
|
||||
#include "Svc/FramingProtocol/FprimeProtocol.hpp"
|
||||
#include "Svc/Health/Health.hpp"
|
||||
|
||||
// Definitions are placed within a namespace named after the deployment
|
||||
|
||||
@ -102,8 +102,14 @@ module Ref {
|
||||
stack size Default.STACK_SIZE \
|
||||
priority 96
|
||||
|
||||
# ComQueue has a deeper queue to be resilient to spikes in com throughput
|
||||
instance comQueue: Svc.ComQueue base id 0x1100 \
|
||||
queue size 50 \
|
||||
stack size Default.STACK_SIZE \
|
||||
priority 100
|
||||
|
||||
instance typeDemo: Ref.TypeDemo base id 0x1100
|
||||
|
||||
instance typeDemo: Ref.TypeDemo base id 0x1200
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Queued component instances
|
||||
@ -137,35 +143,37 @@ module Ref {
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Communications driver. May be swapped with other comm drivers like UART
|
||||
instance comm: Drv.TcpClient base id 0x4000
|
||||
instance comDriver: Drv.TcpClient base id 0x4000
|
||||
|
||||
instance framer: Svc.Framer base id 0x4100
|
||||
instance fatalAdapter: Svc.AssertFatalAdapter base id 0x4100
|
||||
|
||||
instance fatalAdapter: Svc.AssertFatalAdapter base id 0x4200
|
||||
instance fatalHandler: Svc.FatalHandler base id 0x4200
|
||||
|
||||
instance fatalHandler: Svc.FatalHandler base id 0x4300
|
||||
instance commsBufferManager: Svc.BufferManager base id 0x4300
|
||||
|
||||
instance commsBufferManager: Svc.BufferManager base id 0x4400
|
||||
instance posixTime: Svc.PosixTime base id 0x4400
|
||||
|
||||
instance posixTime: Svc.PosixTime base id 0x4500
|
||||
instance rateGroupDriverComp: Svc.RateGroupDriver base id 0x4500
|
||||
|
||||
instance rateGroupDriverComp: Svc.RateGroupDriver base id 0x4600
|
||||
instance recvBuffComp: Ref.RecvBuff base id 0x4600
|
||||
|
||||
instance recvBuffComp: Ref.RecvBuff base id 0x4700
|
||||
instance version: Svc.Version base id 0x4700
|
||||
|
||||
instance version: Svc.Version base id 0x4800
|
||||
instance textLogger: Svc.PassiveTextLogger base id 0x4800
|
||||
|
||||
instance textLogger: Svc.PassiveTextLogger base id 0x4900
|
||||
instance systemResources: Svc.SystemResources base id 0x4900
|
||||
|
||||
instance systemResources: Svc.SystemResources base id 0x4A00
|
||||
instance dpBufferManager: Svc.BufferManager base id 0x4A00
|
||||
|
||||
instance dpBufferManager: Svc.BufferManager base id 0x4B00
|
||||
instance frameAccumulator: Svc.FrameAccumulator base id 0x4B00
|
||||
|
||||
instance frameAccumulator: Svc.FrameAccumulator base id 0x4C00
|
||||
instance deframer: Svc.FprimeDeframer base id 0x4C00
|
||||
|
||||
instance deframer: Svc.FprimeDeframer base id 0x4D00
|
||||
instance fprimeRouter: Svc.FprimeRouter base id 0x4D00
|
||||
|
||||
instance fprimeRouter: Svc.FprimeRouter base id 0x4E00
|
||||
instance fprimeFramer: Svc.FprimeFramer base id 0x4E00
|
||||
|
||||
instance comStub: Svc.ComStub base id 0x4F00
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -4,11 +4,16 @@ module Ref {
|
||||
# Symbolic constants for port numbers
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
enum Ports_RateGroups {
|
||||
rateGroup1
|
||||
rateGroup2
|
||||
rateGroup3
|
||||
}
|
||||
enum Ports_RateGroups {
|
||||
rateGroup1
|
||||
rateGroup2
|
||||
rateGroup3
|
||||
}
|
||||
|
||||
enum Ports_ComPacketQueue {
|
||||
EVENTS,
|
||||
TELEMETRY
|
||||
}
|
||||
|
||||
topology Ref {
|
||||
|
||||
@ -26,7 +31,9 @@ module Ref {
|
||||
instance tlmSend
|
||||
instance cmdDisp
|
||||
instance cmdSeq
|
||||
instance comm
|
||||
instance comDriver
|
||||
instance comStub
|
||||
instance comQueue
|
||||
instance deframer
|
||||
instance eventLogger
|
||||
instance fatalAdapter
|
||||
@ -36,7 +43,7 @@ module Ref {
|
||||
instance fileUplink
|
||||
instance commsBufferManager
|
||||
instance frameAccumulator
|
||||
instance framer
|
||||
instance fprimeFramer
|
||||
instance posixTime
|
||||
instance pingRcvr
|
||||
instance prmDb
|
||||
@ -85,20 +92,28 @@ module Ref {
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
connections Downlink {
|
||||
|
||||
tlmSend.PktSend -> framer.comIn
|
||||
eventLogger.PktSend -> framer.comIn
|
||||
fileDownlink.bufferSendOut -> framer.bufferIn
|
||||
|
||||
framer.framedAllocate -> commsBufferManager.bufferGetCallee
|
||||
framer.framedOut -> comm.$send
|
||||
framer.bufferDeallocate -> fileDownlink.bufferReturn
|
||||
|
||||
comm.deallocate -> commsBufferManager.bufferSendIn
|
||||
|
||||
dpCat.fileOut -> fileDownlink.SendFile
|
||||
fileDownlink.FileComplete -> dpCat.fileDone
|
||||
|
||||
eventLogger.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.EVENTS]
|
||||
tlmSend.PktSend -> comQueue.comPacketQueueIn[Ports_ComPacketQueue.TELEMETRY]
|
||||
fileDownlink.bufferSendOut -> comQueue.bufferQueueIn[0]
|
||||
comQueue.bufferReturnOut[0] -> fileDownlink.bufferReturn
|
||||
|
||||
comQueue.queueSend -> fprimeFramer.dataIn
|
||||
fprimeFramer.dataReturnOut -> comQueue.bufferReturnIn
|
||||
fprimeFramer.comStatusOut -> comQueue.comStatusIn
|
||||
|
||||
fprimeFramer.bufferAllocate -> commsBufferManager.bufferGetCallee
|
||||
fprimeFramer.bufferDeallocate -> commsBufferManager.bufferSendIn
|
||||
|
||||
fprimeFramer.dataOut -> comStub.comDataIn
|
||||
comStub.dataReturnOut -> fprimeFramer.dataReturnIn
|
||||
comStub.comStatusOut -> fprimeFramer.comStatusIn
|
||||
|
||||
comStub.drvDataOut -> comDriver.$send
|
||||
comDriver.dataReturnOut -> comStub.dataReturnIn
|
||||
comDriver.ready -> comStub.drvConnected
|
||||
}
|
||||
|
||||
connections FaultProtection {
|
||||
@ -117,6 +132,7 @@ module Ref {
|
||||
rateGroup1Comp.RateGroupMemberOut[2] -> tlmSend.Run
|
||||
rateGroup1Comp.RateGroupMemberOut[3] -> fileDownlink.Run
|
||||
rateGroup1Comp.RateGroupMemberOut[4] -> systemResources.run
|
||||
rateGroup1Comp.RateGroupMemberOut[5] -> comQueue.run
|
||||
|
||||
# Rate group 2
|
||||
rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup2] -> rateGroup2Comp.CycleIn
|
||||
@ -148,8 +164,9 @@ module Ref {
|
||||
|
||||
connections Uplink {
|
||||
|
||||
comm.allocate -> commsBufferManager.bufferGetCallee
|
||||
comm.$recv -> frameAccumulator.dataIn
|
||||
comDriver.allocate -> commsBufferManager.bufferGetCallee
|
||||
comDriver.$recv -> comStub.drvDataIn
|
||||
comStub.comDataOut -> frameAccumulator.dataIn
|
||||
|
||||
frameAccumulator.frameOut -> deframer.framedIn
|
||||
frameAccumulator.bufferAllocate -> commsBufferManager.bufferGetCallee
|
||||
|
||||
@ -8,6 +8,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PolyIf/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Sched/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Seq/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/WatchDog/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ports/")
|
||||
|
||||
# Components
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ActiveLogger/")
|
||||
@ -35,10 +36,10 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlink/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileManager/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileUplink/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FprimeDeframer/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FprimeFramer/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FprimeProtocol/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FprimeRouter/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FrameAccumulator/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Framer/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FramingProtocol/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/GenericHub/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Health/")
|
||||
@ -52,8 +53,6 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/StaticMemory/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TlmChan/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TlmPacketizer/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SystemResources/")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ports/VersionPorts")
|
||||
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ports/OsTimeEpoch")
|
||||
|
||||
# Text logger components included by default,
|
||||
# but can be disabled if FW_ENABLE_TEXT_LOGGING=0 is desired.
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
#include <Fw/Types/Assert.hpp>
|
||||
#include <Svc/ComQueue/ComQueue.hpp>
|
||||
#include <Fw/Com/ComPacket.hpp>
|
||||
#include "Fw/Types/BasicTypes.hpp"
|
||||
|
||||
namespace Svc {
|
||||
@ -130,22 +131,22 @@ void ComQueue::configure(QueueConfigurationTable queueConfig,
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ComQueue::comQueueIn_handler(const FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
|
||||
// Ensure that the port number of comQueueIn is consistent with the expectation
|
||||
void ComQueue::comPacketQueueIn_handler(const FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
|
||||
// Ensure that the port number of comPacketQueueIn is consistent with the expectation
|
||||
FW_ASSERT(portNum >= 0 && portNum < COM_PORT_COUNT, static_cast<FwAssertArgType>(portNum));
|
||||
(void)this->enqueue(portNum, QueueType::COM_QUEUE, reinterpret_cast<const U8*>(&data), sizeof(Fw::ComBuffer));
|
||||
}
|
||||
|
||||
void ComQueue::buffQueueIn_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
void ComQueue::bufferQueueIn_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
FW_ASSERT(std::numeric_limits<FwIndexType>::max() - COM_PORT_COUNT > portNum);
|
||||
const FwIndexType queueNum = static_cast<FwIndexType>(portNum + COM_PORT_COUNT);
|
||||
// Ensure that the port number of buffQueueIn is consistent with the expectation
|
||||
// Ensure that the port number of bufferQueueIn is consistent with the expectation
|
||||
FW_ASSERT(portNum >= 0 && portNum < BUFFER_PORT_COUNT, static_cast<FwAssertArgType>(portNum));
|
||||
FW_ASSERT(queueNum < TOTAL_PORT_COUNT);
|
||||
bool status =
|
||||
bool success =
|
||||
this->enqueue(queueNum, QueueType::BUFFER_QUEUE, reinterpret_cast<const U8*>(&fwBuffer), sizeof(Fw::Buffer));
|
||||
if (!status) {
|
||||
this->deallocate_out(portNum, fwBuffer);
|
||||
if (!success) {
|
||||
this->bufferReturnOut_out(portNum, fwBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,13 +189,32 @@ void ComQueue::run_handler(const FwIndexType portNum, U32 context) {
|
||||
this->tlmWrite_buffQueueDepth(buffQueueDepth);
|
||||
}
|
||||
|
||||
void ComQueue ::bufferReturnIn_handler(FwIndexType portNum,
|
||||
Fw::Buffer& data,
|
||||
const ComCfg::FrameContext& context) {
|
||||
static_assert(std::numeric_limits<FwIndexType>::is_signed, "FwIndexType must be signed");
|
||||
// For the buffer queues, the index of the queue is portNum offset by COM_PORT_COUNT since
|
||||
// the first COM_PORT_COUNT queues are for ComBuffer. So we have for buffer queues:
|
||||
// queueNum = portNum + COM_PORT_COUNT
|
||||
// Since queueNum is used as APID, we can retrieve the original portNum like such:
|
||||
FwIndexType bufferReturnPortNum = static_cast<FwIndexType>(context.getcomQueueIndex() - ComQueue::COM_PORT_COUNT);
|
||||
// Failing this assert means that context.apid was modified since ComQueue set it, which should not happen
|
||||
FW_ASSERT(bufferReturnPortNum < BUFFER_PORT_COUNT, static_cast<FwAssertArgType>(bufferReturnPortNum));
|
||||
if (bufferReturnPortNum >= 0) {
|
||||
// It is a coding error not to connect the associated bufferReturnOut port for each bufferReturnIn port
|
||||
FW_ASSERT(this->isConnected_bufferReturnOut_OutputPort(bufferReturnPortNum), static_cast<FwAssertArgType>(bufferReturnPortNum));
|
||||
// If this is a buffer port, return the buffer to the BufferDownlink
|
||||
this->bufferReturnOut_out(bufferReturnPortNum, data);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Hook implementations for typed async input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ComQueue::buffQueueIn_overflowHook(FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
void ComQueue::bufferQueueIn_overflowHook(FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
FW_ASSERT(portNum >= 0 && portNum < BUFFER_PORT_COUNT, static_cast<FwAssertArgType>(portNum));
|
||||
this->deallocate_out(portNum, fwBuffer);
|
||||
this->bufferReturnOut_out(portNum, fwBuffer);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@ -231,16 +251,29 @@ bool ComQueue::enqueue(const FwIndexType queueNum, QueueType queueType, const U8
|
||||
return rvStatus;
|
||||
}
|
||||
|
||||
void ComQueue::sendComBuffer(Fw::ComBuffer& comBuffer) {
|
||||
void ComQueue::sendComBuffer(Fw::ComBuffer& comBuffer, FwIndexType queueIndex) {
|
||||
FW_ASSERT(this->m_state == READY);
|
||||
this->comQueueSend_out(0, comBuffer, 0);
|
||||
|
||||
Fw::Buffer outBuffer(comBuffer.getBuffAddr(), static_cast<Fw::Buffer::SizeType>(comBuffer.getBuffLength()));
|
||||
|
||||
// Context APID is set to the queue index for now. A future implementation may want this to be configurable
|
||||
ComCfg::FrameContext context;
|
||||
context.setcomQueueIndex(queueIndex);
|
||||
this->queueSend_out(0, outBuffer, context);
|
||||
// Set state to WAITING for the status to come back
|
||||
this->m_state = WAITING;
|
||||
}
|
||||
|
||||
void ComQueue::sendBuffer(Fw::Buffer& buffer) {
|
||||
void ComQueue::sendBuffer(Fw::Buffer& buffer, FwIndexType queueIndex) {
|
||||
// Retry buffer expected to be cleared as we are either transferring ownership or have already deallocated it.
|
||||
FW_ASSERT(this->m_state == READY);
|
||||
this->buffQueueSend_out(0, buffer);
|
||||
|
||||
// Context APID is set to the queue index for now. A future implementation may want this to be configurable
|
||||
ComCfg::FrameContext context;
|
||||
context.setcomQueueIndex(queueIndex);
|
||||
this->queueSend_out(0, buffer, context);
|
||||
|
||||
// Set state to WAITING for the status to come back
|
||||
this->m_state = WAITING;
|
||||
}
|
||||
|
||||
@ -265,11 +298,11 @@ void ComQueue::processQueue() {
|
||||
if (entry.index < COM_PORT_COUNT) {
|
||||
Fw::ComBuffer comBuffer;
|
||||
queue.dequeue(reinterpret_cast<U8*>(&comBuffer), sizeof(comBuffer));
|
||||
this->sendComBuffer(comBuffer);
|
||||
this->sendComBuffer(comBuffer, entry.index);
|
||||
} else {
|
||||
Fw::Buffer buffer;
|
||||
queue.dequeue(reinterpret_cast<U8*>(&buffer), sizeof(buffer));
|
||||
this->sendBuffer(buffer);
|
||||
this->sendBuffer(buffer, entry.index);
|
||||
}
|
||||
|
||||
// Update the throttle and the index that was just sent
|
||||
|
||||
@ -16,23 +16,24 @@ module Svc {
|
||||
# General ports
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Fw::ComBuffer output port
|
||||
output port comQueueSend: Fw.Com
|
||||
|
||||
@ Fw::Buffer output port
|
||||
output port buffQueueSend: Fw.BufferSend
|
||||
|
||||
@ Port for deallocating Fw::Buffer on queue overflow
|
||||
output port deallocate: Fw.BufferSend
|
||||
@ Port for emitting data ready to be sent
|
||||
output port queueSend: Svc.ComDataWithContext
|
||||
|
||||
@ Port for receiving the status signal
|
||||
async input port comStatusIn: Fw.SuccessCondition
|
||||
|
||||
@ Port array for receiving Fw::ComBuffers
|
||||
async input port comQueueIn: [ComQueueComPorts] Fw.Com drop
|
||||
async input port comPacketQueueIn: [ComQueueComPorts] Fw.Com drop
|
||||
|
||||
@ Port array for receiving Fw::Buffers
|
||||
async input port buffQueueIn: [ComQueueBufferPorts] Fw.BufferSend hook
|
||||
async input port bufferQueueIn: [ComQueueBufferPorts] Fw.BufferSend hook
|
||||
|
||||
@ Port array for returning ownership of Fw::Buffer to its original sender
|
||||
output port bufferReturnOut: [ComQueueBufferPorts] Fw.BufferSend
|
||||
|
||||
# It is appropriate for this port to be sync since it is just a passthrough
|
||||
@ Port for receiving Fw::Buffer whose ownership needs to be handed back
|
||||
sync input port bufferReturnIn: Svc.ComDataWithContext
|
||||
|
||||
@ Port for scheduling telemetry output
|
||||
async input port run: Svc.Sched drop
|
||||
|
||||
@ -24,10 +24,10 @@ namespace Svc {
|
||||
class ComQueue final : public ComQueueComponentBase {
|
||||
public:
|
||||
//!< Count of Fw::Com input ports and thus Fw::Com queues
|
||||
static const FwIndexType COM_PORT_COUNT = ComQueueComponentBase::NUM_COMQUEUEIN_INPUT_PORTS;
|
||||
static const FwIndexType COM_PORT_COUNT = ComQueueComponentBase::NUM_COMPACKETQUEUEIN_INPUT_PORTS;
|
||||
|
||||
//!< Count of Fw::Buffer input ports and thus Fw::Buffer queues
|
||||
static const FwIndexType BUFFER_PORT_COUNT = ComQueueComponentBase::NUM_BUFFQUEUEIN_INPUT_PORTS;
|
||||
static const FwIndexType BUFFER_PORT_COUNT = ComQueueComponentBase::NUM_BUFFERQUEUEIN_INPUT_PORTS;
|
||||
|
||||
static_assert((COM_PORT_COUNT + BUFFER_PORT_COUNT) <= std::numeric_limits<FwIndexType>::max(),
|
||||
"FwIndexType not large enough to hold com and buffer ports");
|
||||
@ -126,27 +126,35 @@ class ComQueue final : public ComQueueComponentBase {
|
||||
|
||||
//! Receive and queue a Fw::Buffer
|
||||
//!
|
||||
void buffQueueIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer& fwBuffer /*!< Buffer containing packet data*/);
|
||||
void bufferQueueIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer& fwBuffer /*!< Buffer containing packet data*/) override;
|
||||
|
||||
//! Receive and queue a Fw::ComBuffer
|
||||
//!
|
||||
void comQueueIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
void comPacketQueueIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::ComBuffer& data, /*!< Buffer containing packet data*/
|
||||
U32 context /*!< Call context value; meaning chosen by user*/
|
||||
);
|
||||
) override;
|
||||
|
||||
//! Handle the status of the last sent message
|
||||
//!
|
||||
void comStatusIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Success& condition /*!<Status of communication state*/
|
||||
);
|
||||
) override;
|
||||
|
||||
//! Schedules the transmission of telemetry
|
||||
//!
|
||||
void run_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
U32 context /*!<The call order*/
|
||||
);
|
||||
) override;
|
||||
|
||||
//! Handler implementation for bufferReturnIn
|
||||
//!
|
||||
//! Port for returning ownership of Fw::Buffer to its sender
|
||||
void bufferReturnIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& data,
|
||||
const ComCfg::FrameContext& context) override;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Hook implementations for typed async input ports
|
||||
@ -154,9 +162,9 @@ class ComQueue final : public ComQueueComponentBase {
|
||||
|
||||
//! Queue overflow hook method that deallocates the fwBuffer
|
||||
//!
|
||||
void buffQueueIn_overflowHook(FwIndexType portNum, //!< The port number
|
||||
void bufferQueueIn_overflowHook(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& fwBuffer //!< The buffer
|
||||
);
|
||||
) override;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
@ -172,17 +180,22 @@ class ComQueue final : public ComQueueComponentBase {
|
||||
|
||||
//! Send a chosen Fw::ComBuffer
|
||||
//!
|
||||
void sendComBuffer(Fw::ComBuffer& comBuffer //!< Reference to buffer to send
|
||||
void sendComBuffer(Fw::ComBuffer& comBuffer, //!< Reference to buffer to send
|
||||
FwIndexType queueIndex //!< Index of the queue emitting the message
|
||||
);
|
||||
|
||||
//! Send a chosen Fw::Buffer
|
||||
//!
|
||||
void sendBuffer(Fw::Buffer& buffer //!< Reference to buffer to send
|
||||
void sendBuffer(Fw::Buffer& buffer, //!< Reference to buffer to send
|
||||
FwIndexType queueIndex //!< Index of the queue emitting the message
|
||||
);
|
||||
|
||||
//! Process the queues to select the next priority message
|
||||
//!
|
||||
void processQueue();
|
||||
|
||||
|
||||
PRIVATE:
|
||||
// ----------------------------------------------------------------------
|
||||
// Member variables
|
||||
// ----------------------------------------------------------------------
|
||||
@ -195,6 +208,7 @@ class ComQueue final : public ComQueueComponentBase {
|
||||
FwEnumStoreType m_allocationId; //!< Component's allocation ID
|
||||
Fw::MemAllocator* m_allocator; //!< Pointer to Fw::MemAllocator instance for deallocation
|
||||
void* m_allocation; //!< Pointer to allocated memory
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Svc
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 33 KiB |
@ -2,18 +2,12 @@
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
`Svc::ComQueue` is an F´ active component that functions as a priority queue of buffer types. Messages are dequeued and
|
||||
forwarded when a `Fw::Success::SUCCESS` signal is received in order of priority. `Fw::Success::FAILURE` signals result
|
||||
in the queues being paused until a following `Fw::Success::SUCCESS` signal.
|
||||
`Svc::ComQueue` is an F´ active component that functions as a priority queue of buffer types. Messages are dequeued and forwarded in order of priority when a `Fw::Success::SUCCESS` signal is received. Receiving a `Fw::Success::FAILURE` results in the queues being paused until a following `Fw::Success::SUCCESS` is received.
|
||||
|
||||
`Svc::ComQueue` is configured with a queue depth and queue priority for each incoming `Fw::Com` and `Fw::Buffer` port by
|
||||
passing in a configuration table at initialization. Queued messages from the highest priority source port are serviced
|
||||
first and a round-robin algorithm is used to balance between ports of shared priority.
|
||||
`Svc::ComQueue` is configured with a queue depth and queue priority for each incoming `Fw::Com` and `Fw::Buffer` port by passing in a configuration table at initialization.
|
||||
Queued messages from the highest priority source port are serviced first and a round-robin algorithm is used to balance between ports of shared priority.
|
||||
|
||||
`Svc::ComQueue` is designed to act alongside instances of the
|
||||
[communication adapter interface](../../../docs/reference/communication-adapter-interface.md) and
|
||||
implements the communication queue
|
||||
[protocol](../../../docs/reference/communication-adapter-interface.md#communication-queue-protocol).
|
||||
`Svc::ComQueue` is designed to act alongside instances of the [communication adapter interface](../../../docs/reference/communication-adapter-interface.md) and implements the communication queue [protocol](../../../docs/reference/communication-adapter-interface.md#communication-queue-protocol).
|
||||
|
||||
## 2. Assumptions
|
||||
|
||||
@ -30,15 +24,15 @@ implements the communication queue
|
||||
| Requirement | Description | Rationale | Verification Method |
|
||||
|------------------|-----------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------|---------------------|
|
||||
| SVC-COMQUEUE-001 | `Svc::ComQueue` shall queue `Fw::Buffer` and `Fw::ComBuffer` received on incoming ports. | The purpose of the queue is to store messages. | Unit Test |
|
||||
| SVC-COMQUEUE-002 | `Svc::ComQueue` shall output exactly one `Fw::Buffer` or `Fw::ComBuffer` message on a received `Fw::Success::SUCCESS` signal. | `Svc::ComQueue` obeys the communication adapter interface protocol. | Unit Test |
|
||||
| SVC-COMQUEUE-003 | `Svc::ComQueue` shall pause sending on the `Fw::Success::FAILURE` and restart on the next `Fw::Success::SUCCESS` signal. | `Svc::ComQueue` should not sent to a failing communication adapter. | Unit Test |
|
||||
| SVC-COMQUEUE-002 | `Svc::ComQueue` shall output exactly one `Fw::Buffer` (wrapping the queued data units) on a received `Fw::Success::SUCCESS` signal. | `Svc::ComQueue` obeys the communication adapter interface protocol. | Unit Test |
|
||||
| SVC-COMQUEUE-003 | `Svc::ComQueue` shall pause sending on the `Fw::Success::FAILURE` and restart on the next `Fw::Success::SUCCESS` signal. | `Svc::ComQueue` should not sent to a failing communication adapter. | Unit Test |
|
||||
| SVC-COMQUEUE-004 | `Svc::ComQueue` shall have a configurable number of `Fw::Com` and `Fw::Buffer` input ports. | `Svc::ComQueue` should be adaptable for a number of projects. | Inspection |
|
||||
| SVC-COMQUEUE-005 | `Svc::ComQueue` shall select and send the next priority `Fw::Buffer` and `Fw::ComBuffer` message in response to `Fw::Success::SUCCESS`. | `Svc::ComQueue` obeys the communication adapter interface protocol. | Unit test |
|
||||
| SVC-COMQUEUE-006 | `Svc::ComQueue` shall periodically telemeter the number of queued messages per-port in response to a `run` port invocation. | `Svc::ComQueue` should provide useful telemetry. | Unit Test |
|
||||
| SVC-COMQUEUE-007 | `Svc::ComQueue` shall emit a queue overflow event for a given port when the configured depth is exceeded. Messages shall be discarded. | `Svc::ComQueue` needs to indicate off-nominal events. | Unit Test |
|
||||
| SVC-COMQUEUE-008 | `Svc::ComQueue` shall implement a round robin approach to balance between ports of the same priority. | Allows projects to balance between a set of queues of similar priority. | Unit Test |
|
||||
| SVC-COMQUEUE-009 | `Svc::ComQueue` shall keep track and throttle queue overflow events per port. | Prevents a flood of queue overflow events. | Unit test |
|
||||
|
||||
comPacketQueueIn
|
||||
## 4. Design
|
||||
The diagram below shows the `Svc::ComQueue` component.
|
||||
|
||||
@ -47,20 +41,17 @@ The diagram below shows the `Svc::ComQueue` component.
|
||||
### 4.1. Ports
|
||||
`Svc::ComQueue` has the following ports:
|
||||
|
||||
| Kind | Name | Port Type | Usage |
|
||||
|---------------|-------------------|---------------------------------------|--------------------------------------------------------|
|
||||
| `output` | `comQueueSend` | `Fw.Com` | Fw::ComBuffer output port |
|
||||
| `output` | `buffQueueSend` | `Fw.BufferSend` | Fw::Buffer output port |
|
||||
| `output` | `deallocate` | `Fw.BufferSend` | Port for deallocating Fw::Buffer on queue overflow |
|
||||
| `async input` | `comStatusIn` | `Fw.SuccessCondition` | Port for receiving the status signal |
|
||||
| `async input` | `comQueueIn` | `[ComQueueComPorts] Fw.Com` | Port array for receiving Fw::ComBuffers |
|
||||
| `async input` | `buffQueueIn` | `[ComQueueBufferPorts] Fw.BufferSend` | Port array for receiving Fw::Buffers |
|
||||
| `async input` | `run` | `Svc.Sched` | Port for scheduling telemetry output |
|
||||
| `event` | `Log` | `Fw.Log` | Port for emitting events |
|
||||
| `text event` | `LogText` | `Fw.LogText` | Port for emitting text events |
|
||||
| `time get` | `Time` | `Fw.Time` | Port for getting the time |
|
||||
| `telemetry` | `Tlm` | `Fw.Tlm` | Port for emitting telemetry |
|
||||
| Kind | Name | Port Type | Usage |
|
||||
|---------------|-------------------|---------------------------------------|----------------------------------------------------------|
|
||||
| `output` | `queueSend` | `Svc.ComDataWithContext` | Port emitting queued messages |
|
||||
| `async input` | `comStatusIn` | `Fw.SuccessCondition` | Port for receiving the status signal |
|
||||
| `async input` | `comPacketQueueIn`| `[ComQueueComPorts] Fw.Com` | Port array for receiving Fw::ComBuffers |
|
||||
| `async input` | `bufferQueueIn` | `[ComQueueBufferPorts] Fw.BufferSend`| Port array for receiving Fw::Buffers |
|
||||
| `sync input` | `bufferReturnIn` | `Svc.ComDataWithContext` | Port for deallocating Fw::Buffer on queue overflow |
|
||||
| `output` | `bufferReturnOut` | `Svc.ComDataWithContext` | Port for deallocating Fw::Buffer on queue overflow |
|
||||
|
||||
> [!NOTE]
|
||||
> ComQueue also has the port instances for autocoded functionality for events, telemetry and time.
|
||||
|
||||
### 4.2. State
|
||||
`Svc::ComQueue` maintains the following state:
|
||||
@ -87,8 +78,8 @@ Buffers are queued when in `WAITING` state.
|
||||
|
||||
### 4.3 Model Configuration
|
||||
`Svc::ComQueue` has the following constants, that are configured in `AcConstants.fpp`:
|
||||
1. `ComQueueComPorts`: number of ports of `Fw.Com` type in the `comQueueIn` port array.
|
||||
2. `ComQueueBufferPorts`: number of ports of `Fw.BufferSend` type in the `buffQueueIn` port array.
|
||||
1. `ComQueueComPorts`: number of ports of `Fw.Com` type in the `comPacketQueueIn` port array.
|
||||
2. `ComQueueBufferPorts`: number of ports of `Fw.BufferSend` type in the `bufferQueueIn` port array.
|
||||
|
||||
### 4.4 Runtime Setup
|
||||
To set up an instance of `ComQueue`, the following needs to be done:
|
||||
@ -104,8 +95,8 @@ and an allocator of `Fw::MemAllocator`. The `configure` method foes the followin
|
||||
|
||||
### 4.5 Port Handlers
|
||||
|
||||
#### 4.5.1 buffQueueIn
|
||||
The `buffQueueIn` port handler receives an `Fw::Buffer` data type and a port number.
|
||||
#### 4.5.1 bufferQueueIn
|
||||
The `bufferQueueIn` port handler receives an `Fw::Buffer` data type and a port number.
|
||||
It does the following:
|
||||
1. Ensures that the port number is between zero and the value of the buffer size
|
||||
2. Enqueue the buffer onto the `m_queues` instance
|
||||
@ -114,8 +105,8 @@ It does the following:
|
||||
In the case where the component is already in `READY` state, this will process the queue immediately after the buffer
|
||||
is added to the queue.
|
||||
|
||||
#### 4.5.2 comQueueIn
|
||||
The `comQueueIn` port handler receives an `Fw::ComBuffer` data type and a port number.
|
||||
#### 4.5.2 comPacketQueueIn
|
||||
The `comPacketQueueIn` port handler receives an `Fw::ComBuffer` data type and a port number.
|
||||
It does the following:
|
||||
1. Ensures that the port number is between zero and the value of the com buffer size
|
||||
2. Enqueue the com buffer onto the `m_queues` instance
|
||||
|
||||
@ -34,6 +34,16 @@ TEST(Nominal, ReadyFirst) {
|
||||
tester.testReadyFirst();
|
||||
}
|
||||
|
||||
TEST(Nominal, ContextData) {
|
||||
Svc::ComQueueTester tester;
|
||||
tester.testContextData();
|
||||
}
|
||||
|
||||
TEST(Nominal, testBufferQueueReturn) {
|
||||
Svc::ComQueueTester tester;
|
||||
tester.testBufferQueueReturn();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
|
||||
@ -49,11 +49,11 @@ void ComQueueTester ::sendByQueueNumber(Fw::Buffer& buffer,
|
||||
Fw::ComBuffer comBuffer(buffer.getData(), buffer.getSize());
|
||||
portNum = queueNum;
|
||||
queueType = QueueType::COM_QUEUE;
|
||||
invoke_to_comQueueIn(portNum, comBuffer, 0);
|
||||
invoke_to_comPacketQueueIn(portNum, comBuffer, 0);
|
||||
} else {
|
||||
portNum = queueNum - ComQueue::COM_PORT_COUNT;
|
||||
queueType = QueueType::BUFFER_QUEUE;
|
||||
invoke_to_buffQueueIn(portNum, buffer);
|
||||
invoke_to_bufferQueueIn(portNum, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,15 +64,14 @@ void ComQueueTester ::emitOne() {
|
||||
}
|
||||
|
||||
void ComQueueTester ::emitOneAndCheck(FwIndexType expectedIndex,
|
||||
QueueType expectedType,
|
||||
Fw::ComBuffer& expectedCom,
|
||||
Fw::Buffer& expectedBuff) {
|
||||
U8* expectedData,
|
||||
FwSizeType expectedSize) {
|
||||
emitOne();
|
||||
|
||||
if (expectedType == QueueType::COM_QUEUE) {
|
||||
ASSERT_from_comQueueSend(expectedIndex, expectedCom, 0);
|
||||
} else {
|
||||
ASSERT_from_buffQueueSend(expectedIndex, expectedBuff);
|
||||
// Check that the data buffers are identical (size + data)
|
||||
Fw::Buffer emittedBuffer = this->fromPortHistory_queueSend->at(expectedIndex).data;
|
||||
ASSERT_EQ(expectedSize, emittedBuffer.getSize());
|
||||
for (FwSizeType i = 0; i < expectedSize; i++) {
|
||||
ASSERT_EQ(emittedBuffer.getData()[i], expectedData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,14 +86,14 @@ void ComQueueTester ::testQueueSend() {
|
||||
configure();
|
||||
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){
|
||||
invoke_to_comQueueIn(portNum, comBuffer, 0);
|
||||
emitOneAndCheck(portNum, QueueType::COM_QUEUE, comBuffer, buffer);
|
||||
invoke_to_comPacketQueueIn(portNum, comBuffer, 0);
|
||||
emitOneAndCheck(portNum, comBuffer.getBuffAddr(), comBuffer.getBuffLength());
|
||||
}
|
||||
clearFromPortHistory();
|
||||
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++){
|
||||
invoke_to_buffQueueIn(portNum, buffer);
|
||||
emitOneAndCheck(portNum, QueueType::BUFFER_QUEUE, comBuffer, buffer);
|
||||
invoke_to_bufferQueueIn(portNum, buffer);
|
||||
emitOneAndCheck(portNum, buffer.getData(), buffer.getSize());
|
||||
}
|
||||
clearFromPortHistory();
|
||||
component.cleanup();
|
||||
@ -107,24 +106,24 @@ void ComQueueTester ::testQueuePause() {
|
||||
configure();
|
||||
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){
|
||||
invoke_to_comQueueIn(portNum, comBuffer, 0);
|
||||
invoke_to_comPacketQueueIn(portNum, comBuffer, 0);
|
||||
// Send a bunch of failures
|
||||
Fw::Success state = Fw::Success::FAILURE;
|
||||
invoke_to_comStatusIn(0, state);
|
||||
invoke_to_comStatusIn(0, state);
|
||||
invoke_to_comStatusIn(0, state);
|
||||
emitOneAndCheck(portNum, QueueType::COM_QUEUE, comBuffer, buffer);
|
||||
emitOneAndCheck(portNum, comBuffer.getBuffAddr(), comBuffer.getBuffLength());
|
||||
}
|
||||
clearFromPortHistory();
|
||||
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++){
|
||||
invoke_to_buffQueueIn(portNum, buffer);
|
||||
invoke_to_bufferQueueIn(portNum, buffer);
|
||||
// Send a bunch of failures
|
||||
Fw::Success state = Fw::Success::FAILURE;
|
||||
invoke_to_comStatusIn(0, state);
|
||||
invoke_to_comStatusIn(0, state);
|
||||
invoke_to_comStatusIn(0, state);
|
||||
emitOneAndCheck(portNum, QueueType::BUFFER_QUEUE, comBuffer, buffer);
|
||||
emitOneAndCheck(portNum, buffer.getData(), buffer.getSize());
|
||||
}
|
||||
clearFromPortHistory();
|
||||
component.cleanup();
|
||||
@ -150,37 +149,26 @@ void ComQueueTester ::testPrioritySend() {
|
||||
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){
|
||||
Fw::ComBuffer comBuffer(&data[portNum][0], BUFFER_LENGTH);
|
||||
invoke_to_comQueueIn(portNum, comBuffer, 0);
|
||||
invoke_to_comPacketQueueIn(portNum, comBuffer, 0);
|
||||
}
|
||||
|
||||
for (FwIndexType portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++) {
|
||||
Fw::Buffer buffer(&data[portNum + ComQueue::COM_PORT_COUNT][0], BUFFER_LENGTH);
|
||||
invoke_to_buffQueueIn(portNum, buffer);
|
||||
invoke_to_bufferQueueIn(portNum, buffer);
|
||||
}
|
||||
|
||||
// Check that nothing has yet been sent
|
||||
ASSERT_from_buffQueueSend_SIZE(0);
|
||||
ASSERT_from_comQueueSend_SIZE(0);
|
||||
ASSERT_from_queueSend_SIZE(0);
|
||||
|
||||
for (FwIndexType index = 0; index < ComQueue::TOTAL_PORT_COUNT; index++) {
|
||||
U8 orderKey;
|
||||
U32 previousComSize = fromPortHistory_comQueueSend->size();
|
||||
U32 previousBufSize = fromPortHistory_buffQueueSend->size();
|
||||
U32 previousSize = fromPortHistory_queueSend->size();
|
||||
emitOne();
|
||||
ASSERT_EQ(fromPortHistory_comQueueSend->size() + fromPortHistory_buffQueueSend->size(), (index + 1));
|
||||
ASSERT_EQ(fromPortHistory_queueSend->size(), (index + 1));
|
||||
// Check that the size changed by exactly one
|
||||
ASSERT_EQ(fromPortHistory_queueSend->size(), (previousSize + 1));
|
||||
|
||||
// Check that the sizes changed by exactly one
|
||||
ASSERT_TRUE((previousComSize == fromPortHistory_comQueueSend->size()) ^
|
||||
(previousBufSize == fromPortHistory_buffQueueSend->size()));
|
||||
|
||||
// Look for which type had arrived
|
||||
if (fromPortHistory_comQueueSend->size() > previousComSize) {
|
||||
orderKey = fromPortHistory_comQueueSend->at(fromPortHistory_comQueueSend->size() - 1).data.getBuffAddr()[0];
|
||||
} else {
|
||||
orderKey =
|
||||
fromPortHistory_buffQueueSend->at(fromPortHistory_buffQueueSend->size() - 1).fwBuffer.getData()[0];
|
||||
|
||||
}
|
||||
orderKey = fromPortHistory_queueSend->at(index).data.getData()[0];
|
||||
ASSERT_EQ(orderKey, index);
|
||||
}
|
||||
clearFromPortHistory();
|
||||
@ -188,6 +176,8 @@ void ComQueueTester ::testPrioritySend() {
|
||||
}
|
||||
|
||||
void ComQueueTester::testExternalQueueOverflow() {
|
||||
// "External" queue is ComQueue's managed queue for input Com/Buffers
|
||||
// as opposed to the "internal" message queue for async input ports
|
||||
ComQueue::QueueConfigurationTable configurationTable;
|
||||
ComQueueDepth expectedComDepth;
|
||||
BuffQueueDepth expectedBuffDepth;
|
||||
@ -212,21 +202,22 @@ void ComQueueTester::testExternalQueueOverflow() {
|
||||
for (FwIndexType queueNum = 0; queueNum < ComQueue::TOTAL_PORT_COUNT; queueNum++) {
|
||||
QueueType overflow_type;
|
||||
FwIndexType portNum;
|
||||
// queue[portNum].depth + 2 to deliberately cause overflow and check throttle of exactly 1
|
||||
// queue[portNum].depth + 2 to deliberately cause overflow of 2, in order to also test the throttle
|
||||
for (FwSizeType msgCount = 0; msgCount < configurationTable.entries[queueNum].depth + 2; msgCount++) {
|
||||
sendByQueueNumber(buffer, queueNum, portNum, overflow_type);
|
||||
dispatchAll();
|
||||
}
|
||||
|
||||
if (QueueType::BUFFER_QUEUE == overflow_type) {
|
||||
ASSERT_from_deallocate_SIZE(2);
|
||||
ASSERT_from_deallocate(0, buffer);
|
||||
ASSERT_from_deallocate(1, buffer);
|
||||
}
|
||||
|
||||
// Throttle should make it that we emitted only 1 event, even though we overflowed twice
|
||||
ASSERT_EVENTS_QueueOverflow_SIZE(1);
|
||||
ASSERT_EVENTS_QueueOverflow(0, overflow_type, portNum);
|
||||
|
||||
if (QueueType::BUFFER_QUEUE == overflow_type) {
|
||||
// Two messages overflowed, so two buffers should be returned
|
||||
ASSERT_from_bufferReturnOut_SIZE(2);
|
||||
ASSERT_from_bufferReturnOut(0, buffer);
|
||||
ASSERT_from_bufferReturnOut(1, buffer);
|
||||
}
|
||||
|
||||
// Drain a message, and see if throttle resets
|
||||
emitOne();
|
||||
|
||||
@ -236,10 +227,12 @@ void ComQueueTester::testExternalQueueOverflow() {
|
||||
dispatchAll();
|
||||
|
||||
if (QueueType::BUFFER_QUEUE == overflow_type) {
|
||||
ASSERT_from_deallocate_SIZE(3);
|
||||
ASSERT_from_deallocate(2, buffer);
|
||||
// Third message overflowed, so third bufferReturnOut
|
||||
ASSERT_from_bufferReturnOut_SIZE(3);
|
||||
ASSERT_from_bufferReturnOut(2, buffer);
|
||||
}
|
||||
|
||||
// emitOne() reset the throttle, then overflow again. So expect a second overflow event
|
||||
ASSERT_EVENTS_QueueOverflow_SIZE(2);
|
||||
ASSERT_EVENTS_QueueOverflow(1, overflow_type, portNum);
|
||||
|
||||
@ -260,6 +253,7 @@ void ComQueueTester::testExternalQueueOverflow() {
|
||||
}
|
||||
|
||||
void ComQueueTester::testInternalQueueOverflow() {
|
||||
// Internal queue is the message queue for async input ports
|
||||
U8 data[BUFFER_LENGTH] = {0xde, 0xad, 0xbe};
|
||||
Fw::Buffer buffer(data, sizeof(data));
|
||||
|
||||
@ -277,15 +271,15 @@ void ComQueueTester::testInternalQueueOverflow() {
|
||||
// send one more to overflow the queue
|
||||
sendByQueueNumber(buffer, queueNum, portNum, overflow_type);
|
||||
|
||||
ASSERT_from_deallocate_SIZE(1);
|
||||
ASSERT_from_deallocate(0, buffer);
|
||||
ASSERT_from_bufferReturnOut_SIZE(1);
|
||||
ASSERT_from_bufferReturnOut(0, buffer);
|
||||
|
||||
// send another
|
||||
sendByQueueNumber(buffer, queueNum, portNum, overflow_type);
|
||||
|
||||
ASSERT_from_deallocate_SIZE(2);
|
||||
ASSERT_from_deallocate(0, buffer);
|
||||
ASSERT_from_deallocate(1, buffer);
|
||||
ASSERT_from_bufferReturnOut_SIZE(2);
|
||||
ASSERT_from_bufferReturnOut(0, buffer);
|
||||
ASSERT_from_bufferReturnOut(1, buffer);
|
||||
|
||||
component.cleanup();
|
||||
}
|
||||
@ -298,36 +292,79 @@ void ComQueueTester ::testReadyFirst() {
|
||||
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){
|
||||
emitOne();
|
||||
invoke_to_comQueueIn(portNum, comBuffer, 0);
|
||||
invoke_to_comPacketQueueIn(portNum, comBuffer, 0);
|
||||
dispatchAll();
|
||||
ASSERT_from_comQueueSend(portNum, comBuffer, 0);
|
||||
|
||||
Fw::Buffer emittedBuffer = this->fromPortHistory_queueSend->at(portNum).data;
|
||||
ASSERT_EQ(emittedBuffer.getSize(), comBuffer.getBuffLength());
|
||||
for (FwSizeType i = 0; i < emittedBuffer.getSize(); i++) {
|
||||
ASSERT_EQ(emittedBuffer.getData()[i], comBuffer.getBuffAddr()[i]);
|
||||
}
|
||||
}
|
||||
clearFromPortHistory();
|
||||
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++){
|
||||
emitOne();
|
||||
invoke_to_buffQueueIn(portNum, buffer);
|
||||
invoke_to_bufferQueueIn(portNum, buffer);
|
||||
dispatchAll();
|
||||
ASSERT_from_buffQueueSend(portNum, buffer);
|
||||
Fw::Buffer emittedBuffer = this->fromPortHistory_queueSend->at(portNum).data;
|
||||
ASSERT_EQ(emittedBuffer.getSize(), buffer.getSize());
|
||||
for (FwSizeType i = 0; i < buffer.getSize(); i++) {
|
||||
ASSERT_EQ(buffer.getData()[i], emittedBuffer.getData()[i]);
|
||||
}
|
||||
}
|
||||
clearFromPortHistory();
|
||||
component.cleanup();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
void ComQueueTester ::testContextData() {
|
||||
U8 data[BUFFER_LENGTH] = {0xde, 0xad, 0xbe};
|
||||
Fw::ComBuffer comBuffer(&data[0], sizeof(data));
|
||||
Fw::Buffer buffer(&data[0], sizeof(data));
|
||||
configure();
|
||||
|
||||
void ComQueueTester ::from_buffQueueSend_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
this->pushFromPortEntry_buffQueueSend(fwBuffer);
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){
|
||||
invoke_to_comPacketQueueIn(portNum, comBuffer, 0);
|
||||
emitOne();
|
||||
// Currently, the APID is set to the queue index, which is the same as the port number for COM ports
|
||||
FwIndexType expectedApid = portNum;
|
||||
auto emittedContext = this->fromPortHistory_queueSend->at(portNum).context;
|
||||
ASSERT_EQ(expectedApid, emittedContext.getcomQueueIndex());
|
||||
}
|
||||
clearFromPortHistory();
|
||||
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++){
|
||||
invoke_to_bufferQueueIn(portNum, buffer);
|
||||
emitOne();
|
||||
// APID is queue index, which is COM_PORT_COUNT + portNum for BUFFER ports
|
||||
FwIndexType expectedApid = portNum + ComQueue::COM_PORT_COUNT;
|
||||
auto emittedContext = this->fromPortHistory_queueSend->at(portNum).context;
|
||||
ASSERT_EQ(expectedApid, emittedContext.getcomQueueIndex());
|
||||
}
|
||||
clearFromPortHistory();
|
||||
component.cleanup();
|
||||
}
|
||||
|
||||
void ComQueueTester ::from_comQueueSend_handler(const FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
|
||||
this->pushFromPortEntry_comQueueSend(data, context);
|
||||
}
|
||||
void ComQueueTester ::testBufferQueueReturn() {
|
||||
U8 data[BUFFER_LENGTH] = {0xde, 0xad, 0xbe};
|
||||
Fw::Buffer buffer(&data[0], sizeof(data));
|
||||
ComCfg::FrameContext context;
|
||||
configure();
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper methods
|
||||
// ----------------------------------------------------------------------
|
||||
for(FwIndexType portNum = 0; portNum < ComQueue::TOTAL_PORT_COUNT; portNum++){
|
||||
clearFromPortHistory();
|
||||
context.setcomQueueIndex(portNum);
|
||||
invoke_to_bufferReturnIn(0, buffer, context);
|
||||
// APIDs that correspond to an buffer originating from a Fw.Com port
|
||||
// do no get deallocated – APIDs that correspond to a Fw.Buffer do
|
||||
if (portNum < ComQueue::COM_PORT_COUNT) {
|
||||
ASSERT_from_bufferReturnOut_SIZE(0);
|
||||
} else {
|
||||
ASSERT_from_bufferReturnOut_SIZE(1);
|
||||
ASSERT_from_bufferReturnOut(0, buffer);
|
||||
}
|
||||
}
|
||||
component.cleanup();
|
||||
}
|
||||
|
||||
} // end namespace Svc
|
||||
|
||||
@ -59,9 +59,8 @@ class ComQueueTester : public ComQueueGTestBase {
|
||||
void emitOne();
|
||||
|
||||
void emitOneAndCheck(FwIndexType expectedIndex,
|
||||
QueueType expectedType,
|
||||
Fw::ComBuffer& expectedCom,
|
||||
Fw::Buffer& expectedBuff);
|
||||
U8* expectedData,
|
||||
FwSizeType expectedDataSize);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Tests
|
||||
@ -79,22 +78,9 @@ class ComQueueTester : public ComQueueGTestBase {
|
||||
|
||||
void testReadyFirst();
|
||||
|
||||
private:
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
// ----------------------------------------------------------------------
|
||||
void testContextData();
|
||||
|
||||
//! Handler for from_buffQueueSend
|
||||
//!
|
||||
void from_buffQueueSend_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer& fwBuffer);
|
||||
|
||||
//! Handler for from_comQueueSend
|
||||
//!
|
||||
void from_comQueueSend_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::ComBuffer& data, /*!< Buffer containing packet data*/
|
||||
U32 context /*!< Call context value; meaning chosen by user*/
|
||||
);
|
||||
void testBufferQueueReturn();
|
||||
|
||||
private:
|
||||
// ----------------------------------------------------------------------
|
||||
@ -117,6 +103,7 @@ class ComQueueTester : public ComQueueGTestBase {
|
||||
//! The component under test
|
||||
//!
|
||||
ComQueue component;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Svc
|
||||
|
||||
@ -10,6 +10,9 @@ set(SOURCE_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ComStub.fpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ComStub.cpp"
|
||||
)
|
||||
set(MOD_DEPS
|
||||
Fw/Logger
|
||||
)
|
||||
register_fprime_module()
|
||||
|
||||
set(UT_SOURCE_FILES
|
||||
@ -20,4 +23,5 @@ set(UT_SOURCE_FILES
|
||||
set(UT_MOD_DEPS
|
||||
STest
|
||||
)
|
||||
set(UT_AUTO_HELPERS ON)
|
||||
register_fprime_ut()
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
// ======================================================================
|
||||
|
||||
#include <Svc/ComStub/ComStub.hpp>
|
||||
#include <Fw/Logger/Logger.hpp>
|
||||
#include "Fw/Types/Assert.hpp"
|
||||
#include "Fw/Types/BasicTypes.hpp"
|
||||
|
||||
@ -14,7 +15,7 @@ namespace Svc {
|
||||
// Construction, initialization, and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ComStub::ComStub(const char* const compName) : ComStubComponentBase(compName), m_reinitialize(true) {}
|
||||
ComStub::ComStub(const char* const compName) : ComStubComponentBase(compName), m_reinitialize(true), m_retry_count(0) {}
|
||||
|
||||
ComStub::~ComStub() {}
|
||||
|
||||
@ -22,33 +23,51 @@ ComStub::~ComStub() {}
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Drv::SendStatus ComStub::comDataIn_handler(const FwIndexType portNum, Fw::Buffer& sendBuffer) {
|
||||
FW_ASSERT(!this->m_reinitialize || !this->isConnected_comStatus_OutputPort(0)); // A message should never get here if we need to reinitialize is needed
|
||||
Drv::SendStatus driverStatus = Drv::SendStatus::SEND_RETRY;
|
||||
for (FwIndexType i = 0; driverStatus == Drv::SendStatus::SEND_RETRY && i < RETRY_LIMIT; i++) {
|
||||
driverStatus = this->drvDataOut_out(0, sendBuffer);
|
||||
}
|
||||
FW_ASSERT(driverStatus != Drv::SendStatus::SEND_RETRY); // If it is still in retry state, there is no good answer
|
||||
Fw::Success comSuccess = (driverStatus.e == Drv::SendStatus::SEND_OK) ? Fw::Success::SUCCESS : Fw::Success::FAILURE;
|
||||
this->m_reinitialize = driverStatus.e != Drv::SendStatus::SEND_OK;
|
||||
if (this->isConnected_comStatus_OutputPort(0)) {
|
||||
this->comStatus_out(0, comSuccess);
|
||||
}
|
||||
return Drv::SendStatus::SEND_OK; // Always send ok to deframer as it does not handle this anyway
|
||||
void ComStub::comDataIn_handler(const FwIndexType portNum, Fw::Buffer& sendBuffer, const ComCfg::FrameContext& context) {
|
||||
FW_ASSERT(!this->m_reinitialize || !this->isConnected_comStatusOut_OutputPort(0)); // A message should never get here if we need to reinitialize is needed
|
||||
this->m_storedContext = context; // Store the context of the current message
|
||||
this->drvDataOut_out(0, sendBuffer);
|
||||
}
|
||||
|
||||
void ComStub::drvConnected_handler(const FwIndexType portNum) {
|
||||
Fw::Success radioSuccess = Fw::Success::SUCCESS;
|
||||
if (this->isConnected_comStatus_OutputPort(0) && m_reinitialize) {
|
||||
if (this->isConnected_comStatusOut_OutputPort(0) && m_reinitialize) {
|
||||
this->m_reinitialize = false;
|
||||
this->comStatus_out(0, radioSuccess);
|
||||
this->comStatusOut_out(0, radioSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
void ComStub::drvDataIn_handler(const FwIndexType portNum,
|
||||
Fw::Buffer& recvBuffer,
|
||||
const Drv::RecvStatus& recvStatus) {
|
||||
this->comDataOut_out(0, recvBuffer, recvStatus);
|
||||
const Drv::ByteStreamStatus& recvStatus) {
|
||||
if (recvStatus.e == Drv::ByteStreamStatus::OP_OK) {
|
||||
this->comDataOut_out(0, recvBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void ComStub ::dataReturnIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& fwBuffer, //!< The buffer
|
||||
const Drv::ByteStreamStatus& sendStatus) {
|
||||
if (sendStatus != Drv::ByteStreamStatus::SEND_RETRY) {
|
||||
// Not retrying - return buffer ownership and send status
|
||||
this->dataReturnOut_out(0, fwBuffer, this->m_storedContext);
|
||||
this->m_reinitialize = sendStatus.e != Drv::ByteStreamStatus::OP_OK;
|
||||
this->m_retry_count = 0; // Reset the retry count
|
||||
Fw::Success comSuccess = (sendStatus.e == Drv::ByteStreamStatus::OP_OK) ? Fw::Success::SUCCESS : Fw::Success::FAILURE;
|
||||
this->comStatusOut_out(0, comSuccess);
|
||||
} else {
|
||||
// Driver indicates we should retry (SEND_RETRY)
|
||||
if (this->m_retry_count < this->RETRY_LIMIT) {
|
||||
// If we have not yet retried more than the retry limit, attempt to retry
|
||||
this->m_retry_count++;
|
||||
this->drvDataOut_out(0, fwBuffer);
|
||||
} else {
|
||||
// If retried too many times, return buffer and log failure
|
||||
this->dataReturnOut_out(0, fwBuffer, this->m_storedContext);
|
||||
Fw::Logger::log("ComStub RETRY_LIMIT exceeded, skipped sending data");
|
||||
this->m_retry_count = 0; // Reset the retry count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Svc
|
||||
|
||||
@ -10,10 +10,14 @@ module Svc {
|
||||
@ Ready signal when driver is connected
|
||||
sync input port drvConnected: Drv.ByteStreamReady
|
||||
|
||||
@ Data received from driver
|
||||
sync input port drvDataIn: Drv.ByteStreamRecv
|
||||
@ Receive (read) data from driver. This gets forwarded to comDataOut
|
||||
sync input port drvDataIn: Drv.ByteStreamData
|
||||
|
||||
@ Send (write) data to the driver. This gets invoked on comDataIn invocation
|
||||
output port drvDataOut: Fw.BufferSend
|
||||
|
||||
@ Callback from drvDataOut (retrieving status and ownership of sent buffer)
|
||||
sync input port dataReturnIn: Drv.ByteStreamData
|
||||
|
||||
@ Data going to the underlying driver
|
||||
output port drvDataOut: Drv.ByteStreamSend
|
||||
}
|
||||
}
|
||||
@ -7,11 +7,14 @@
|
||||
#ifndef Svc_ComStub_HPP
|
||||
#define Svc_ComStub_HPP
|
||||
|
||||
#include "Drv/ByteStreamDriverModel/ByteStreamStatusEnumAc.hpp"
|
||||
#include "Svc/ComStub/ComStubComponentAc.hpp"
|
||||
|
||||
namespace Svc {
|
||||
|
||||
class ComStub final : public ComStubComponentBase {
|
||||
friend class ComStubTester; //!< Allow UT Tester to access private members
|
||||
|
||||
public:
|
||||
const FwIndexType RETRY_LIMIT = 10;
|
||||
// ----------------------------------------------------------------------
|
||||
@ -34,8 +37,11 @@ class ComStub final : public ComStubComponentBase {
|
||||
|
||||
//! Handler implementation for comDataIn
|
||||
//!
|
||||
Drv::SendStatus comDataIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer& sendBuffer) override;
|
||||
//! Comms data is coming in meaning there is a request for ComStub to send data on the wire
|
||||
//! For ComStub, this means we send the data to the underlying driver (e.g. TCP/UDP/UART)
|
||||
void comDataIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer& sendBuffer,
|
||||
const ComCfg::FrameContext& context) override;
|
||||
|
||||
//! Handler implementation for drvConnected
|
||||
//!
|
||||
@ -43,11 +49,22 @@ class ComStub final : public ComStubComponentBase {
|
||||
|
||||
//! Handler implementation for drvDataIn
|
||||
//!
|
||||
//! Data is coming in from the driver (meaning it has been read from the wire).
|
||||
//! ComStub forwards this to the comDataOut port
|
||||
void drvDataIn_handler(const FwIndexType portNum,
|
||||
/*!< The port number*/ Fw::Buffer& recvBuffer,
|
||||
const Drv::RecvStatus& recvStatus) override;
|
||||
const Drv::ByteStreamStatus& recvStatus) override;
|
||||
|
||||
bool m_reinitialize; //!< Stores if a ready signal is needed on connection
|
||||
//! Handler implementation for dataReturnIn
|
||||
//!
|
||||
//! Buffer ownership and status returning from a Driver "send" operation
|
||||
void dataReturnIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& fwBuffer, //!< The buffer
|
||||
const Drv::ByteStreamStatus& recvStatus) override;
|
||||
|
||||
bool m_reinitialize; //!< Stores if a ready signal is needed on connection
|
||||
ComCfg::FrameContext m_storedContext; //!< Stores the context of the current message
|
||||
FwIndexType m_retry_count; //!< Counts the number of retries of the current message
|
||||
};
|
||||
|
||||
} // end namespace Svc
|
||||
|
||||
@ -55,8 +55,8 @@ be useful
|
||||
|
||||
| Kind | Name | Port Type | Usage |
|
||||
|--------------|----------------|-----------------------|-----------------------------------------------------------------------------------|
|
||||
| `sync input` | `comDataIn` | `Drv.ByteStreamSend` | Port receiving `Fw::Buffer`s for transmission out `drvDataOut` |
|
||||
| `output` | `comStatus` | `Svc.ComStatus` | Port indicating success or failure to attached `Svc::ComQueue` |
|
||||
| `sync input` | `comDataIn` | `Svc.ComDataWithContext` | Port receiving `Fw::Buffer`s for transmission out `drvDataOut` |
|
||||
| `output` | `comStatusOut` | `Svc.ComStatus` | Port indicating success or failure to attached `Svc::ComQueue` |
|
||||
| `output` | `comDataOut` | `Drv.ByteStreamRecv` | Port providing received `Fw::Buffers` to a potential `Svc::Deframer` |
|
||||
|
||||
**Byte Stream Driver Model Ports**
|
||||
@ -81,13 +81,13 @@ response to a driver reconnection event. This is to implement the Communication
|
||||
The `comDataIn` port handler receives an `Fw::Buffer` from the F´ system for transmission to the ground. Typically, it
|
||||
is connected to the output of the `Svc::Framer` component. In this `Svc::ComStub` implementation, it passes this
|
||||
`Fw::Buffer` directly to the `drvDataOut` port. It will retry when that port responds with a `RETRY` request. Otherwise,
|
||||
the `comStatus` port will be invoked to indicate success or failure. Retries attempts are limited before the port
|
||||
the `comStatusOut` port will be invoked to indicate success or failure. Retries attempts are limited before the port
|
||||
asserts.
|
||||
|
||||
#### 4.3.1 drvConnected
|
||||
|
||||
This port receives the connected signal from the driver and responds with exactly one `READY` invocation to the
|
||||
`comStatus` port. This starts downlink. This occurs each time the driver reconnects.
|
||||
`comStatusOut` port. This starts downlink. This occurs each time the driver reconnects.
|
||||
|
||||
#### 4.3.1 drvDataIn
|
||||
|
||||
|
||||
@ -25,6 +25,11 @@ TEST(OffNominal, Retry) {
|
||||
tester.test_retry();
|
||||
}
|
||||
|
||||
TEST(OffNominal, RetryReset) {
|
||||
Svc::ComStubTester tester;
|
||||
tester.test_retry_reset();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
|
||||
@ -7,12 +7,6 @@
|
||||
#include "ComStubTester.hpp"
|
||||
#include <STest/Pick/Pick.hpp>
|
||||
|
||||
#define INSTANCE 0
|
||||
#define MAX_HISTORY_SIZE 100
|
||||
#define RETRIES 3
|
||||
|
||||
U8 storage[RETRIES][10240];
|
||||
|
||||
namespace Svc {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@ -21,8 +15,8 @@ namespace Svc {
|
||||
|
||||
ComStubTester ::ComStubTester()
|
||||
: ComStubGTestBase("Tester", MAX_HISTORY_SIZE),
|
||||
m_component("ComStub"),
|
||||
m_send_mode(Drv::SendStatus::SEND_OK),
|
||||
component("ComStub"),
|
||||
m_send_mode(Drv::ByteStreamStatus::OP_OK),
|
||||
m_retries(0) {
|
||||
this->initComponents();
|
||||
this->connectPorts();
|
||||
@ -47,74 +41,112 @@ void ComStubTester ::fill(Fw::Buffer& buffer_to_fill) {
|
||||
void ComStubTester ::test_initial() {
|
||||
Fw::Success condition = Fw::Success::SUCCESS;
|
||||
invoke_to_drvConnected(0);
|
||||
ASSERT_from_comStatus_SIZE(1);
|
||||
ASSERT_from_comStatus(0, condition);
|
||||
this->fromPortHistory_comStatus->clear();
|
||||
ASSERT_from_comStatusOut_SIZE(1);
|
||||
ASSERT_from_comStatusOut(0, condition);
|
||||
this->fromPortHistory_comStatusOut->clear();
|
||||
}
|
||||
|
||||
void ComStubTester ::test_basic() {
|
||||
this->test_initial();
|
||||
Fw::Buffer buffer(storage[0], sizeof(storage[0]));
|
||||
U8 storage[8];
|
||||
Fw::Buffer buffer(storage, sizeof(storage));
|
||||
Fw::Success condition = Fw::Success::SUCCESS;
|
||||
ComCfg::FrameContext context;
|
||||
this->fill(buffer);
|
||||
|
||||
// Downlink
|
||||
ASSERT_EQ(invoke_to_comDataIn(0, buffer), Drv::SendStatus::SEND_OK);
|
||||
invoke_to_comDataIn(0, buffer, context);
|
||||
ASSERT_from_drvDataOut_SIZE(1);
|
||||
ASSERT_from_drvDataOut(0, buffer);
|
||||
ASSERT_from_comStatus(0, condition);
|
||||
|
||||
// Uplink
|
||||
Drv::RecvStatus status = Drv::RecvStatus::RECV_OK;
|
||||
invoke_to_drvDataIn(0, buffer, status);
|
||||
invoke_to_drvDataIn(0, buffer, Drv::ByteStreamStatus::OP_OK);
|
||||
ASSERT_from_comDataOut_SIZE(1);
|
||||
ASSERT_from_comDataOut(0, buffer, status);
|
||||
ASSERT_from_comDataOut(0, buffer);
|
||||
}
|
||||
|
||||
void ComStubTester ::test_fail() {
|
||||
this->test_initial();
|
||||
Fw::Buffer buffer(storage[0], sizeof(storage[0]));
|
||||
U8 storage[8];
|
||||
Fw::Buffer buffer(storage, sizeof(storage));
|
||||
this->fill(buffer);
|
||||
Fw::Success condition = Fw::Success::FAILURE;
|
||||
m_send_mode = Drv::SendStatus::SEND_ERROR;
|
||||
m_send_mode = Drv::ByteStreamStatus::OTHER_ERROR;
|
||||
ComCfg::FrameContext context;
|
||||
|
||||
// Downlink
|
||||
ASSERT_EQ(invoke_to_comDataIn(0, buffer), Drv::SendStatus::SEND_OK);
|
||||
invoke_to_comDataIn(0, buffer, context);
|
||||
ASSERT_from_drvDataOut_SIZE(1);
|
||||
ASSERT_from_drvDataOut(0, buffer);
|
||||
ASSERT_from_drvDataOut_SIZE(1);
|
||||
ASSERT_from_comStatus(0, condition);
|
||||
|
||||
// Uplink
|
||||
Drv::RecvStatus status = Drv::RecvStatus::RECV_ERROR;
|
||||
invoke_to_drvDataIn(0, buffer, status);
|
||||
ASSERT_from_comDataOut_SIZE(1);
|
||||
ASSERT_from_comDataOut(0, buffer, status);
|
||||
invoke_to_drvDataIn(0, buffer, Drv::ByteStreamStatus::OTHER_ERROR);
|
||||
ASSERT_from_comDataOut_SIZE(0); // receiving failure should not send anything
|
||||
}
|
||||
|
||||
void ComStubTester ::test_retry() {
|
||||
this->test_initial();
|
||||
Fw::Buffer buffers[RETRIES];
|
||||
Fw::Success condition = Fw::Success::SUCCESS;
|
||||
m_send_mode = Drv::SendStatus::SEND_RETRY;
|
||||
FwIndexType MAX_ITERS = this->component.RETRY_LIMIT + 1;
|
||||
|
||||
for (U32 i = 0; i < RETRIES; i++) {
|
||||
// Make small individual buffers for testing
|
||||
U8 storage[MAX_ITERS][8];
|
||||
Fw::Buffer buffers[MAX_ITERS];
|
||||
for (FwIndexType i = 0; i < MAX_ITERS; i++) {
|
||||
buffers[i].setData(storage[i]);
|
||||
buffers[i].setSize(sizeof(storage[i]));
|
||||
buffers[i].setContext(i);
|
||||
buffers[i].setContext(static_cast<U32>(i));
|
||||
this->fill(buffers[i]);
|
||||
invoke_to_comDataIn(0, buffers[i]);
|
||||
ASSERT_from_drvDataOut_SIZE((i + 1) * RETRIES);
|
||||
m_retries = 0;
|
||||
}
|
||||
ASSERT_from_drvDataOut_SIZE(RETRIES * RETRIES);
|
||||
ASSERT_from_comStatus_SIZE(3);
|
||||
for (U32 i = 0; i < RETRIES; i++) {
|
||||
for (U32 j = 0; j < RETRIES; j++) {
|
||||
ASSERT_from_drvDataOut((i * RETRIES) + j, buffers[i]);
|
||||
}
|
||||
ASSERT_from_comStatus(i, condition);
|
||||
// Retrying for as many times as the RETRY_LIMIT should be ok
|
||||
for (FwIndexType i = 0; i < this->component.RETRY_LIMIT; i++) {
|
||||
invoke_to_dataReturnIn(0, buffers[i], Drv::ByteStreamStatus::SEND_RETRY);
|
||||
// Test we have indeed retried (data sent on drvDataOut)
|
||||
ASSERT_from_drvDataOut_SIZE(static_cast<U32>(i + 1));
|
||||
ASSERT_from_drvDataOut(static_cast<U32>(i), buffers[i]);
|
||||
}
|
||||
ASSERT_from_drvDataOut_SIZE(static_cast<U32>(this->component.RETRY_LIMIT));
|
||||
ASSERT_EQ(this->component.m_retry_count, this->component.RETRY_LIMIT);
|
||||
// Retry one more time should block from retrying and reset retry count
|
||||
invoke_to_dataReturnIn(0, buffers[MAX_ITERS - 1], Drv::ByteStreamStatus::SEND_RETRY);
|
||||
ASSERT_from_drvDataOut_SIZE(static_cast<U32>(this->component.RETRY_LIMIT)); // no drvDataOut sent when SEND_RETRY
|
||||
ASSERT_from_dataReturnOut_SIZE(1); // buffer ownership was returned
|
||||
ASSERT_EQ(this->component.m_retry_count, 0);
|
||||
}
|
||||
|
||||
void ComStubTester ::test_retry_reset() {
|
||||
this->test_initial();
|
||||
FwIndexType MAX_ITERS = this->component.RETRY_LIMIT + 1;
|
||||
U32 expected_drvDataOut_count = 0;
|
||||
|
||||
// Make small individual buffers for testing
|
||||
U8 storage[MAX_ITERS][8];
|
||||
Fw::Buffer buffers[MAX_ITERS];
|
||||
for (FwIndexType i = 0; i < MAX_ITERS; i++) {
|
||||
buffers[i].setData(storage[i]);
|
||||
buffers[i].setSize(sizeof(storage[i]));
|
||||
buffers[i].setContext(static_cast<U32>(i));
|
||||
this->fill(buffers[i]);
|
||||
}
|
||||
|
||||
// Retrying for as many times as the RETRY_LIMIT should be ok
|
||||
for (FwIndexType i = 0; i < this->component.RETRY_LIMIT; i++) {
|
||||
invoke_to_dataReturnIn(0, buffers[i], Drv::ByteStreamStatus::SEND_RETRY);
|
||||
ASSERT_from_drvDataOut(expected_drvDataOut_count, buffers[i]);
|
||||
expected_drvDataOut_count++; // trick: increment now to use as index prior and size after
|
||||
ASSERT_from_drvDataOut_SIZE(expected_drvDataOut_count);
|
||||
}
|
||||
// Now, we receive a OP_OK, which should not retry (drvDataOut should not be called) and reset the retry count
|
||||
ASSERT_from_drvDataOut_SIZE(expected_drvDataOut_count); // no drvDataOut sent when OP_OK
|
||||
invoke_to_dataReturnIn(0, buffers[0], Drv::ByteStreamStatus::OP_OK);
|
||||
ASSERT_from_drvDataOut_SIZE(expected_drvDataOut_count); // no drvDataOut sent when OP_OK
|
||||
// Now that retry count is reset, we can retry again without a problem
|
||||
for (FwIndexType i = 0; i < this->component.RETRY_LIMIT; i++) {
|
||||
invoke_to_dataReturnIn(0, buffers[i], Drv::ByteStreamStatus::SEND_RETRY);
|
||||
ASSERT_from_drvDataOut(expected_drvDataOut_count, buffers[i]);
|
||||
expected_drvDataOut_count++; // trick: increment now to use as index prior and size after
|
||||
ASSERT_from_drvDataOut_SIZE(expected_drvDataOut_count);
|
||||
}
|
||||
ASSERT_from_drvDataOut_SIZE(expected_drvDataOut_count); // no drvDataOut sent when OP_OK
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
@ -122,51 +154,17 @@ void ComStubTester ::test_retry() {
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ComStubTester ::from_comDataOut_handler(const FwIndexType portNum,
|
||||
Fw::Buffer& recvBuffer,
|
||||
const Drv::RecvStatus& recvStatus) {
|
||||
this->pushFromPortEntry_comDataOut(recvBuffer, recvStatus);
|
||||
Fw::Buffer& recvBuffer) {
|
||||
this->pushFromPortEntry_comDataOut(recvBuffer);
|
||||
}
|
||||
|
||||
void ComStubTester ::from_comStatus_handler(const FwIndexType portNum, Fw::Success& condition) {
|
||||
this->pushFromPortEntry_comStatus(condition);
|
||||
void ComStubTester ::from_comStatusOut_handler(const FwIndexType portNum, Fw::Success& condition) {
|
||||
this->pushFromPortEntry_comStatusOut(condition);
|
||||
}
|
||||
|
||||
Drv::SendStatus ComStubTester ::from_drvDataOut_handler(const FwIndexType portNum, Fw::Buffer& sendBuffer) {
|
||||
void ComStubTester ::from_drvDataOut_handler(const FwIndexType portNum, Fw::Buffer& sendBuffer) {
|
||||
this->pushFromPortEntry_drvDataOut(sendBuffer);
|
||||
m_retries = (m_send_mode == Drv::SendStatus::SEND_RETRY) ? (m_retries + 1) : m_retries;
|
||||
if (m_retries < RETRIES) {
|
||||
return m_send_mode;
|
||||
}
|
||||
return Drv::SendStatus::SEND_OK;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ComStubTester ::connectPorts() {
|
||||
// comDataIn
|
||||
this->connect_to_comDataIn(0, this->m_component.get_comDataIn_InputPort(0));
|
||||
|
||||
// drvConnected
|
||||
this->connect_to_drvConnected(0, this->m_component.get_drvConnected_InputPort(0));
|
||||
|
||||
// drvDataIn
|
||||
this->connect_to_drvDataIn(0, this->m_component.get_drvDataIn_InputPort(0));
|
||||
|
||||
// comDataOut
|
||||
this->m_component.set_comDataOut_OutputPort(0, this->get_from_comDataOut(0));
|
||||
|
||||
// comStatus
|
||||
this->m_component.set_comStatus_OutputPort(0, this->get_from_comStatus(0));
|
||||
|
||||
// drvDataOut
|
||||
this->m_component.set_drvDataOut_OutputPort(0, this->get_from_drvDataOut(0));
|
||||
}
|
||||
|
||||
void ComStubTester ::initComponents() {
|
||||
this->init();
|
||||
this->m_component.init(INSTANCE);
|
||||
}
|
||||
|
||||
} // end namespace Svc
|
||||
|
||||
@ -13,6 +13,12 @@
|
||||
namespace Svc {
|
||||
|
||||
class ComStubTester : public ComStubGTestBase {
|
||||
|
||||
// Maximum size of histories storing events, telemetry, and port outputs
|
||||
static const FwSizeType MAX_HISTORY_SIZE = 30;
|
||||
|
||||
// Instance ID supplied to the component instance under test
|
||||
static const FwEnumStoreType TEST_INSTANCE_ID = 0;
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
@ -50,6 +56,10 @@ class ComStubTester : public ComStubGTestBase {
|
||||
//!
|
||||
void test_retry();
|
||||
|
||||
//! Tests the retry -> reset -> retry again
|
||||
//!
|
||||
void test_retry_reset();
|
||||
|
||||
private:
|
||||
// ----------------------------------------------------------------------
|
||||
// Handlers for typed from ports
|
||||
@ -58,19 +68,18 @@ class ComStubTester : public ComStubGTestBase {
|
||||
//! Handler for from_comDataOut
|
||||
//!
|
||||
void from_comDataOut_handler(const FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& recvBuffer,
|
||||
const Drv::RecvStatus& recvStatus);
|
||||
Fw::Buffer& recvBuffer);
|
||||
|
||||
//! Handler for from_comStatus
|
||||
//! Handler for from_comStatusOut
|
||||
//!
|
||||
void from_comStatus_handler(const FwIndexType portNum, //!< The port number
|
||||
void from_comStatusOut_handler(const FwIndexType portNum, //!< The port number
|
||||
Fw::Success& condition //!< Status of communication state
|
||||
);
|
||||
|
||||
//! Handler for from_drvDataOut
|
||||
//!
|
||||
Drv::SendStatus from_drvDataOut_handler(const FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& sendBuffer);
|
||||
void from_drvDataOut_handler(const FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& sendBuffer);
|
||||
|
||||
private:
|
||||
// ----------------------------------------------------------------------
|
||||
@ -92,8 +101,8 @@ class ComStubTester : public ComStubGTestBase {
|
||||
|
||||
//! The component under test
|
||||
//!
|
||||
ComStub m_component;
|
||||
Drv::SendStatus m_send_mode; //! Send mode
|
||||
ComStub component;
|
||||
Drv::ByteStreamStatus m_send_mode; //! Send mode
|
||||
U32 m_retries; //! Number of retries to test
|
||||
};
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ FprimeDeframer ::~FprimeDeframer() {}
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FprimeDeframer ::framedIn_handler(FwIndexType portNum, Fw::Buffer& data, Fw::Buffer& context) {
|
||||
void FprimeDeframer ::framedIn_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context) {
|
||||
if (data.getSize() < FprimeProtocol::FrameHeader::SERIALIZED_SIZE + FprimeProtocol::FrameTrailer::SERIALIZED_SIZE) {
|
||||
// Incoming buffer is not long enough to contain a valid frame (header+trailer)
|
||||
this->log_WARNING_HI_InvalidBufferReceived();
|
||||
|
||||
@ -38,7 +38,7 @@ class FprimeDeframer final : public FprimeDeframerComponentBase {
|
||||
//! and pass the deframed data to the deframed output port.
|
||||
void framedIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& data,
|
||||
Fw::Buffer& context) override;
|
||||
const ComCfg::FrameContext& context) override;
|
||||
};
|
||||
|
||||
} // namespace Svc
|
||||
|
||||
@ -16,7 +16,7 @@ The `Svc::FprimeDeframer` does not support deframing multiple packets in a singl
|
||||
|
||||
### Frame validation
|
||||
|
||||
The passed-in `data` field (of type `Fw::Buffer`) of the `Fw.DataWithContext` input port is validated for the following conditions:
|
||||
The passed-in `data` field (of type `Fw::Buffer`) of the `Svc.ComDataWithContext` input port is validated for the following conditions:
|
||||
- The buffer is large enough to contain the header and trailer
|
||||
- The buffer starts with the F´ start word
|
||||
- The buffer length is equal to (or larger than) the packet length field in the frame header
|
||||
@ -41,7 +41,7 @@ The below diagram shows a typical configuration in which the `Svc::FprimeDeframe
|
||||
```mermaid
|
||||
classDiagram
|
||||
class FprimeDeframer~PassiveComponent~ {
|
||||
+ void framedIn_handler(FwIndexType portNum, Fw::Buffer& data, Fw::Buffer& context)
|
||||
+ void framedIn_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context)
|
||||
}
|
||||
```
|
||||
|
||||
@ -57,6 +57,6 @@ SVC-DEFRAMER-002 | `Svc::FprimeDeframer` shall deallocate input buffers that are
|
||||
|
||||
| Kind | Name | Type | Description |
|
||||
|---|---|---|---|
|
||||
| `guarded input` | framedIn | `Fw.DataWithContext` | Receives a frame with optional context data |
|
||||
| `output` | deframedOut | `Fw.DataWithContext` | Receives a frame with optional context data |
|
||||
| `guarded input` | framedIn | `Svc.ComDataWithContext` | Receives a frame with optional context data |
|
||||
| `output` | deframedOut | `Svc.ComDataWithContext` | Receives a frame with optional context data |
|
||||
| `output` | bufferDeallocate | `Fw.BufferSend` | Port for deallocating dropped frames |
|
||||
|
||||
@ -122,7 +122,7 @@ void FprimeDeframerTester::injectChecksum(U8* data, FwSizeType size) {
|
||||
}
|
||||
|
||||
void FprimeDeframerTester::mockReceiveData(U8* data, FwSizeType size) {
|
||||
Fw::Buffer nullContext;
|
||||
ComCfg::FrameContext nullContext;
|
||||
Fw::Buffer buffer(data, static_cast<Fw::Buffer::SizeType>(size));
|
||||
this->invoke_to_framedIn(0, buffer, nullContext);
|
||||
}
|
||||
|
||||
32
Svc/FprimeFramer/CMakeLists.txt
Normal file
32
Svc/FprimeFramer/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
####
|
||||
# FPrime CMakeLists.txt:
|
||||
#
|
||||
# SOURCE_FILES: combined list of source and autocoding files
|
||||
# MOD_DEPS: (optional) module dependencies
|
||||
# UT_SOURCE_FILES: list of source files for unit tests
|
||||
#
|
||||
# More information in the F´ CMake API documentation:
|
||||
# https://fprime.jpl.nasa.gov/latest/documentation/reference
|
||||
#
|
||||
####
|
||||
|
||||
set(SOURCE_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/FprimeFramer.fpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/FprimeFramer.cpp"
|
||||
)
|
||||
|
||||
set(MOD_DEPS
|
||||
Svc/FprimeProtocol
|
||||
)
|
||||
|
||||
register_fprime_module()
|
||||
|
||||
|
||||
### Unit Tests ###
|
||||
set(UT_SOURCE_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/FprimeFramer.fpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/test/ut/FprimeFramerTestMain.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/test/ut/FprimeFramerTester.cpp"
|
||||
)
|
||||
set(UT_AUTO_HELPERS ON)
|
||||
register_fprime_ut()
|
||||
75
Svc/FprimeFramer/FprimeFramer.cpp
Normal file
75
Svc/FprimeFramer/FprimeFramer.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// ======================================================================
|
||||
// \title FprimeFramer.cpp
|
||||
// \author thomas-bc
|
||||
// \brief cpp file for FprimeFramer component implementation class
|
||||
// ======================================================================
|
||||
|
||||
#include "Svc/FprimeFramer/FprimeFramer.hpp"
|
||||
#include "Svc/FprimeProtocol/FrameHeaderSerializableAc.hpp"
|
||||
#include "Svc/FprimeProtocol/FrameTrailerSerializableAc.hpp"
|
||||
#include "Utils/Hash/Hash.hpp"
|
||||
|
||||
namespace Svc {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Component construction and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
FprimeFramer ::FprimeFramer(const char* const compName) : FprimeFramerComponentBase(compName) {}
|
||||
|
||||
FprimeFramer ::~FprimeFramer() {}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handler implementations for typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FprimeFramer ::dataIn_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context) {
|
||||
FprimeProtocol::FrameHeader header;
|
||||
FprimeProtocol::FrameTrailer trailer;
|
||||
|
||||
// Full size of the frame will be size of header + data + trailer
|
||||
FwSizeType frameSize =
|
||||
FprimeProtocol::FrameHeader::SERIALIZED_SIZE + data.getSize() + FprimeProtocol::FrameTrailer::SERIALIZED_SIZE;
|
||||
FW_ASSERT(data.getSize() <= std::numeric_limits<FprimeProtocol::TokenType>::max(), static_cast<FwAssertArgType>(frameSize));
|
||||
FW_ASSERT(frameSize <= std::numeric_limits<Fw::Buffer::SizeType>::max(), static_cast<FwAssertArgType>(frameSize));
|
||||
|
||||
// Allocate frame buffer
|
||||
Fw::Buffer frameBuffer = this->bufferAllocate_out(0, static_cast<Fw::Buffer::SizeType>(frameSize));
|
||||
auto frameSerializer = frameBuffer.getSerializer();
|
||||
Fw::SerializeStatus status;
|
||||
|
||||
// Serialize the header
|
||||
// 0xDEADBEEF is already set as the default value for the header startWord field in the FPP type definition
|
||||
header.setlengthField(data.getSize());
|
||||
status = frameSerializer.serialize(header);
|
||||
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
|
||||
|
||||
// Serialize the data
|
||||
status = frameSerializer.serialize(data.getData(), data.getSize(), Fw::Serialization::OMIT_LENGTH);
|
||||
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
|
||||
|
||||
// Serialize the trailer (with CRC computation)
|
||||
Utils::HashBuffer hashBuffer;
|
||||
Utils::Hash::hash(frameBuffer.getData(), frameSize - HASH_DIGEST_LENGTH, hashBuffer);
|
||||
trailer.setcrcField(hashBuffer.asBigEndianU32());
|
||||
status = frameSerializer.serialize(trailer);
|
||||
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
|
||||
|
||||
// Send the full frame out - this port shall always be connected
|
||||
this->dataOut_out(0, frameBuffer, context);
|
||||
// Return original (unframed) data buffer ownership back to its sender - always connected
|
||||
this->dataReturnOut_out(0, data, context);
|
||||
}
|
||||
|
||||
void FprimeFramer ::comStatusIn_handler(FwIndexType portNum, Fw::Success& condition) {
|
||||
if (this->isConnected_comStatusOut_OutputPort(portNum)) {
|
||||
this->comStatusOut_out(portNum, condition);
|
||||
}
|
||||
}
|
||||
|
||||
void FprimeFramer ::dataReturnIn_handler(FwIndexType portNum, Fw::Buffer& frameBuffer, const ComCfg::FrameContext& context) {
|
||||
// dataReturnIn is the allocated buffer coming back from the ComManager (e.g. ComStub) component
|
||||
this->bufferDeallocate_out(0, frameBuffer);
|
||||
}
|
||||
|
||||
} // namespace Svc
|
||||
24
Svc/FprimeFramer/FprimeFramer.fpp
Normal file
24
Svc/FprimeFramer/FprimeFramer.fpp
Normal file
@ -0,0 +1,24 @@
|
||||
module Svc {
|
||||
@ Framer implementation for the F Prime protocol
|
||||
passive component FprimeFramer {
|
||||
|
||||
include "../Interfaces/FramerInterface.fppi"
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Allocation of buffers
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Port for allocating buffers to hold framed data
|
||||
output port bufferAllocate: Fw.BufferGet
|
||||
|
||||
@ Port for deallocating buffers allocated for framed data
|
||||
output port bufferDeallocate: Fw.BufferSend
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Standard AC Ports
|
||||
# ----------------------------------------------------------------------
|
||||
@ Port for requesting the current time
|
||||
time get port timeCaller
|
||||
|
||||
}
|
||||
}
|
||||
66
Svc/FprimeFramer/FprimeFramer.hpp
Normal file
66
Svc/FprimeFramer/FprimeFramer.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
// ======================================================================
|
||||
// \title FprimeFramer.hpp
|
||||
// \author thomas-bc
|
||||
// \brief hpp file for FprimeFramer component implementation class
|
||||
// ======================================================================
|
||||
|
||||
#ifndef Svc_FprimeFramer_HPP
|
||||
#define Svc_FprimeFramer_HPP
|
||||
|
||||
#include "Svc/FprimeFramer/FprimeFramerComponentAc.hpp"
|
||||
|
||||
namespace Svc {
|
||||
|
||||
class FprimeFramer final : public FprimeFramerComponentBase {
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
// Component construction and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Construct FprimeFramer object
|
||||
FprimeFramer(const char* const compName //!< The component name
|
||||
);
|
||||
|
||||
//! Destroy FprimeFramer object
|
||||
~FprimeFramer();
|
||||
|
||||
PRIVATE:
|
||||
// ----------------------------------------------------------------------
|
||||
// Handler implementations for typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Handler implementation for comStatusIn
|
||||
//!
|
||||
//! Port receiving the general status from the downstream component
|
||||
//! indicating it is ready or not-ready for more input
|
||||
void comStatusIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Success& condition //!< Condition success/failure
|
||||
) override;
|
||||
|
||||
//! Handler implementation for dataIn
|
||||
//!
|
||||
//! Port to receive data to frame, in a Fw::Buffer with optional context
|
||||
void dataIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& data,
|
||||
const ComCfg::FrameContext& context) override;
|
||||
|
||||
//! Handler implementation for dataReturnIn
|
||||
//!
|
||||
//! Buffer coming from a deallocate call in a ComDriver component
|
||||
void dataReturnIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& data,
|
||||
const ComCfg::FrameContext& context) override;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Helper function to send the framed data out of the component
|
||||
//! This sequentially calls both frameDataOut and frameStreamOut ports if connected
|
||||
void framedOut_helper(Fw::Buffer& frameBuffer,
|
||||
const ComCfg::FrameContext& context);
|
||||
};
|
||||
|
||||
} // namespace Svc
|
||||
|
||||
#endif
|
||||
BIN
Svc/FprimeFramer/docs/img/framer-topology.png
Normal file
BIN
Svc/FprimeFramer/docs/img/framer-topology.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
42
Svc/FprimeFramer/docs/sdd.md
Normal file
42
Svc/FprimeFramer/docs/sdd.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Svc::FprimeFramer
|
||||
|
||||
The `Svc::FprimeFramer` is an implementation of the [FramerInterface](../../Interfaces/docs/sdd.md) for the F Prime protocol.
|
||||
|
||||
It receives data (an F´ packet) on input and produces an [F´ frame](../../FprimeProtocol/docs/sdd.md) on its output port as a result. Please refer to the [F Prime frame specification](../../FprimeProtocol/docs/sdd.md) for details on the frame format.
|
||||
|
||||
### Diagrams
|
||||
|
||||
Below is the common configuration in which the `Svc::FprimeFramer` can be used. It is receiving packets from a [`Svc::ComQueue`](../../ComQueue/docs/sdd.md) and passes frames to a [Communications Adapter](../../Interfaces/docs/sdd.md), such as a Radio manager component (or a [`Svc::ComStub`](../../ComStub/docs/sdd.md)), for transmission.
|
||||
|
||||

|
||||
|
||||
## Internals
|
||||
|
||||
The `Svc::FprimeFramer` receives data packets of type `Svc.ComDataWithContext`. This type contains both a `Fw::Buffer` containing the packet data, and a `context: FrameContext` that contains contextual information about the data packet (such as an APID). In the default configuration (using Svc::ComQueue), the `context` is used to determine whether a packet is coming from the ComQueue's Fw::Buffer queue (as opposed to ComPacket queue). If it is, the original data packet `Fw::Buffer` is returned back to its original sender.
|
||||
|
||||
On receiving a data packet, the `Svc::FprimeFramer` performs the following actions:
|
||||
|
||||
1. Allocates a new _`outBuffer`_ (of type `Fw::Buffer`) to hold the F´ frame, of size _`size(dataPacket) + size(FprimeHeader) + size(FprimeTrailer)`_
|
||||
2. Serializes the F´ start word (`0xDEADBEEF`) and length token (`size(dataPacket)`) into _`outBuffer`_
|
||||
3. Serializes the F´ packet data into _`outBuffer`_
|
||||
4. Computes and serializes a CRC32 checksum into _`outBuffer`_
|
||||
5. Emits the _`outBuffer`_ on the `dataOut` output port. Ownership of _`outBuffer`_ is handed to the receiver
|
||||
5. Transfer ownership of input _`dataPacket`_ to the `dataReturnOut` port. This usually should be connected to the same component that sent the original packet to `dataIn`.
|
||||
|
||||
## Port Descriptions
|
||||
|
||||
| Kind | Name | Port Type | Usage |
|
||||
|---|---|---|---|
|
||||
| `guarded input` | `dataIn` | `Svc.ComDataWithContext` | Port to receive data to frame, in a Fw::Buffer with optional context|
|
||||
| `output` | `dataOut` | `Svc.ComDataWithContext` | Port to output framed data, with optional context, for follow-up framing|
|
||||
| `sync input` | `comStatusIn` | `Fw.SuccessCondition` | Port receiving the general status from the downstream component|
|
||||
| `output` | `comStatusOut` | `Fw.SuccessCondition` | Port receiving indicating the status of framer for receiving more data|
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Description | Validation |
|
||||
|---|---|---|
|
||||
| SVC-FPRIME_FRAMER-001 | `Svc::FprimeFramer` shall accept data buffers (packets) stored in `Fw::Buffer` through its `dataIn` input port | Unit Test |
|
||||
| SVC-FPRIME_FRAMER-002 | `Svc::FprimeFramer` shall emit one F Prime frame on its `framedOut` output port for each packet received on `dataIn` input port | Unit Test |
|
||||
| SVC-FPRIME_FRAMER-003 | `Svc::FprimeFramer` shall emit F Prime frames that conforms to the [F´ frame specification](../../FprimeProtocol/docs/sdd.md) | Unit Test |
|
||||
|
||||
27
Svc/FprimeFramer/test/ut/FprimeFramerTestMain.cpp
Normal file
27
Svc/FprimeFramer/test/ut/FprimeFramerTestMain.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
// ======================================================================
|
||||
// \title FprimeFramerTestMain.cpp
|
||||
// \author thomas-bc
|
||||
// \brief cpp file for FprimeFramer component test main function
|
||||
// ======================================================================
|
||||
|
||||
#include "FprimeFramerTester.hpp"
|
||||
|
||||
TEST(Nominal, testComStatusPassThrough) {
|
||||
Svc::FprimeFramerTester tester;
|
||||
tester.testComStatusPassThrough();
|
||||
}
|
||||
|
||||
TEST(Nominal, testFrameDeallocation) {
|
||||
Svc::FprimeFramerTester tester;
|
||||
tester.testFrameDeallocation();
|
||||
}
|
||||
|
||||
TEST(Nominal, testNominalFraming) {
|
||||
Svc::FprimeFramerTester tester;
|
||||
tester.testNominalFraming();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
93
Svc/FprimeFramer/test/ut/FprimeFramerTester.cpp
Normal file
93
Svc/FprimeFramer/test/ut/FprimeFramerTester.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
// ======================================================================
|
||||
// \title FprimeFramerTester.cpp
|
||||
// \author thomas-bc
|
||||
// \brief cpp file for FprimeFramer component test harness implementation class
|
||||
// ======================================================================
|
||||
|
||||
#include "FprimeFramerTester.hpp"
|
||||
#include "Svc/FprimeProtocol/FrameHeaderSerializableAc.hpp"
|
||||
#include "Svc/FprimeProtocol/FrameTrailerSerializableAc.hpp"
|
||||
|
||||
namespace Svc {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
FprimeFramerTester ::FprimeFramerTester()
|
||||
: FprimeFramerGTestBase("FprimeFramerTester", FprimeFramerTester::MAX_HISTORY_SIZE), component("FprimeFramer") {
|
||||
this->initComponents();
|
||||
this->connectPorts();
|
||||
}
|
||||
|
||||
FprimeFramerTester ::~FprimeFramerTester() {}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FprimeFramerTester ::testFrameDeallocation() {
|
||||
// When receiving a buffer on dataReturnIn, the buffer should be deallocated
|
||||
Fw::Buffer buffer;
|
||||
ComCfg::FrameContext context;
|
||||
this->invoke_to_dataReturnIn(0, buffer, context);
|
||||
ASSERT_from_bufferDeallocate_SIZE(1);
|
||||
ASSERT_from_bufferDeallocate(0, buffer);
|
||||
}
|
||||
|
||||
void FprimeFramerTester ::testComStatusPassThrough() {
|
||||
// Send a status message to the component
|
||||
Fw::Success inputStatus = Fw::Success::SUCCESS;
|
||||
this->invoke_to_comStatusIn(0, inputStatus);
|
||||
ASSERT_from_comStatusOut_SIZE(1);
|
||||
ASSERT_from_comStatusOut(0, inputStatus); // at index 0, received SUCCESS
|
||||
inputStatus = Fw::Success::FAILURE;
|
||||
this->invoke_to_comStatusIn(0, inputStatus);
|
||||
ASSERT_from_comStatusOut_SIZE(2);
|
||||
ASSERT_from_comStatusOut(1, inputStatus); // at index 1, received FAILURE
|
||||
}
|
||||
|
||||
void FprimeFramerTester ::testNominalFraming() {
|
||||
U8 bufferData[100];
|
||||
Fw::Buffer buffer(bufferData, sizeof(bufferData));
|
||||
ComCfg::FrameContext context;
|
||||
|
||||
|
||||
// Fill the buffer with some data
|
||||
for (U32 i = 0; i < sizeof(bufferData); ++i) {
|
||||
bufferData[i] = static_cast<U8>(i);
|
||||
}
|
||||
|
||||
// Send the buffer to the component
|
||||
this->invoke_to_dataIn(0, buffer, context);
|
||||
ASSERT_from_dataOut_SIZE(1); // One frame emitted
|
||||
ASSERT_from_dataReturnOut_SIZE(1); // Original data buffer ownership returned
|
||||
|
||||
Fw::Buffer outputBuffer = this->fromPortHistory_dataOut->at(0).data;
|
||||
// Check the size of the output buffer
|
||||
ASSERT_EQ(outputBuffer.getSize(), sizeof(bufferData) + FprimeProtocol::FrameHeader::SERIALIZED_SIZE + FprimeProtocol::FrameTrailer::SERIALIZED_SIZE);
|
||||
// Check header
|
||||
FprimeProtocol::FrameHeader defaultHeader;
|
||||
FprimeProtocol::FrameHeader outputHeader;
|
||||
outputBuffer.getDeserializer().deserialize(outputHeader);
|
||||
ASSERT_EQ(outputHeader.getstartWord(), defaultHeader.getstartWord());
|
||||
ASSERT_EQ(outputHeader.getlengthField(), sizeof(bufferData));
|
||||
// Check data
|
||||
for (U32 i = 0; i < sizeof(bufferData); ++i) {
|
||||
ASSERT_EQ(outputBuffer.getData()[i + FprimeProtocol::FrameHeader::SERIALIZED_SIZE], bufferData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Test Harness: Handler implementations for output ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Fw::Buffer FprimeFramerTester::from_bufferAllocate_handler(FwIndexType portNum, U32 size){
|
||||
this->pushFromPortEntry_bufferAllocate(size);
|
||||
this->m_buffer.setData(this->m_buffer_slot);
|
||||
this->m_buffer.setSize(size);
|
||||
::memset(this->m_buffer.getData(), 0, size);
|
||||
return this->m_buffer;
|
||||
}
|
||||
|
||||
} // namespace Svc
|
||||
83
Svc/FprimeFramer/test/ut/FprimeFramerTester.hpp
Normal file
83
Svc/FprimeFramer/test/ut/FprimeFramerTester.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
// ======================================================================
|
||||
// \title FprimeFramerTester.hpp
|
||||
// \author thomas-bc
|
||||
// \brief hpp file for FprimeFramer component test harness implementation class
|
||||
// ======================================================================
|
||||
|
||||
#ifndef Svc_FprimeFramerTester_HPP
|
||||
#define Svc_FprimeFramerTester_HPP
|
||||
|
||||
#include "Svc/FprimeFramer/FprimeFramer.hpp"
|
||||
#include "Svc/FprimeFramer/FprimeFramerGTestBase.hpp"
|
||||
|
||||
namespace Svc {
|
||||
|
||||
class FprimeFramerTester final : public FprimeFramerGTestBase {
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
// Constants
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// Maximum size of histories storing events, telemetry, and port outputs
|
||||
static const FwSizeType MAX_HISTORY_SIZE = 10;
|
||||
|
||||
// Instance ID supplied to the component instance under test
|
||||
static const FwEnumStoreType TEST_INSTANCE_ID = 0;
|
||||
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Construct object FprimeFramerTester
|
||||
FprimeFramerTester();
|
||||
|
||||
//! Destroy object FprimeFramerTester
|
||||
~FprimeFramerTester();
|
||||
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
// Tests
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Test pass through of comStatusIn to comStatusOut
|
||||
void testComStatusPassThrough();
|
||||
|
||||
//! Test deallocation of data
|
||||
void testFrameDeallocation();
|
||||
|
||||
//! Test framing of data
|
||||
void testNominalFraming();
|
||||
|
||||
private:
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper functions
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Connect ports
|
||||
void connectPorts();
|
||||
|
||||
//! Initialize components
|
||||
void initComponents();
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Test Harness: Handler implementations for output ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Fw::Buffer from_bufferAllocate_handler(FwIndexType portNum, U32 size) override;
|
||||
|
||||
private:
|
||||
// ----------------------------------------------------------------------
|
||||
// Member variables
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! The component under test
|
||||
FprimeFramer component;
|
||||
|
||||
U8 m_buffer_slot[2048];
|
||||
Fw::Buffer m_buffer; // buffer to be returned by mocked allocate call
|
||||
};
|
||||
|
||||
} // namespace Svc
|
||||
|
||||
#endif
|
||||
@ -1,9 +1,12 @@
|
||||
module Svc {
|
||||
module FprimeProtocol {
|
||||
|
||||
type TokenType = U32
|
||||
|
||||
@ Describes the frame header format for the F Prime communications protocol
|
||||
struct FrameHeader {
|
||||
startWord: U32,
|
||||
lengthField: U32,
|
||||
startWord: TokenType,
|
||||
lengthField: TokenType,
|
||||
} default {
|
||||
startWord = 0xdeadbeef
|
||||
}
|
||||
@ -14,3 +17,4 @@ module FprimeProtocol {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ FprimeRouter ::~FprimeRouter() {}
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FprimeRouter ::dataIn_handler(FwIndexType portNum, Fw::Buffer& packetBuffer, Fw::Buffer& contextBuffer) {
|
||||
void FprimeRouter ::dataIn_handler(FwIndexType portNum, Fw::Buffer& packetBuffer, const ComCfg::FrameContext& context) {
|
||||
// Read the packet type from the packet buffer
|
||||
FwPacketDescriptorType packetType = Fw::ComPacket::FW_PACKET_UNKNOWN;
|
||||
Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;
|
||||
@ -71,7 +71,7 @@ void FprimeRouter ::dataIn_handler(FwIndexType portNum, Fw::Buffer& packetBuffer
|
||||
// Packet type is not known to the F Prime protocol. If the unknownDataOut port is
|
||||
// connected, forward packet and context for further processing
|
||||
if (this->isConnected_unknownDataOut_OutputPort(0)) {
|
||||
this->unknownDataOut_out(0, packetBuffer, contextBuffer);
|
||||
this->unknownDataOut_out(0, packetBuffer, context);
|
||||
// Transfer ownership of the packetBuffer to the receiver
|
||||
deallocate = false;
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ module Svc {
|
||||
include "../Interfaces/RouterInterface.fppi"
|
||||
|
||||
@ Port for forwarding non-recognized packet types
|
||||
output port unknownDataOut: Fw.DataWithContext
|
||||
output port unknownDataOut: Svc.ComDataWithContext
|
||||
|
||||
@ Port for deallocating buffers
|
||||
output port bufferDeallocate: Fw.BufferSend
|
||||
|
||||
@ -33,7 +33,7 @@ class FprimeRouter final : public FprimeRouterComponentBase {
|
||||
//! Receiving Fw::Buffer from Deframer
|
||||
void dataIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& packetBuffer, //!< The packet buffer
|
||||
Fw::Buffer& contextBuffer //!< The context buffer
|
||||
const ComCfg::FrameContext& context //!< The context object
|
||||
) override;
|
||||
|
||||
// ! Handler for input port cmdResponseIn
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
The `Svc::FprimeRouter` component routes F´ packets (such as command or file packets) to other components.
|
||||
|
||||
The `Svc::FprimeRouter` component receives F´ packets (as [Fw::Buffer](../../../Fw/Buffer/docs/sdd.md) objects) and routes them to other components through synchronous port calls. The input port of type `Fw.DataWithContext` passes this Fw.Buffer object along with optional context data which can help for routing. The current F Prime protocol does not use this context data, but is nevertheless present in the interface for compatibility with other protocols which may for example pass APIDs in the frame headers.
|
||||
The `Svc::FprimeRouter` component receives F´ packets (as [Fw::Buffer](../../../Fw/Buffer/docs/sdd.md) objects) and routes them to other components through synchronous port calls. The input port of type `Svc.ComDataWithContext` passes this Fw.Buffer object along with optional context data which can help for routing. The current F Prime protocol does not use this context data, but is nevertheless present in the interface for compatibility with other protocols which may for example pass APIDs in the frame headers.
|
||||
|
||||
The `Svc::FprimeRouter` component supports `Fw::ComPacket::FW_PACKET_COMMAND` and `Fw::ComPacket::FW_PACKET_FILE` packet types. Unknown packet types are forwarded on the `unknownDataOut` port, which a project-specific component can connect to for custom routing. In the case of unknown data being forwarded, the ownership of the packet data `Fw::Buffer` object is passed to the receiver.
|
||||
|
||||
@ -31,10 +31,10 @@ classDiagram
|
||||
|
||||
| Name | Description | Type |
|
||||
|---|---|---|
|
||||
| `dataIn: Fw.DataWithContext` | Receiving Fw::Buffer with context buffer from Deframer | `guarded input` |
|
||||
| `dataIn: Svc.ComDataWithContext` | Receiving Fw::Buffer with context buffer from Deframer | `guarded input` |
|
||||
| `commandOut: Fw.Com` | Port for sending command packets as Fw::ComBuffers | `output` |
|
||||
| `fileOut: Fw.BufferSend` | Port for sending file packets as Fw::Buffer (ownership passed to receiver) | `output` |
|
||||
| `unknownDataOut: Fw.DataWithContext` | Port forwarding unknown data (useful for adding custom routing rules with a project-defined router) | `output` |
|
||||
| `unknownDataOut: Svc.ComDataWithContext` | Port forwarding unknown data (useful for adding custom routing rules with a project-defined router) | `output` |
|
||||
| `output`| bufferDeallocate | `Fw.BufferSend` | Port for deallocating buffers once routed |
|
||||
|
||||
## Requirements
|
||||
|
||||
@ -76,10 +76,9 @@ void FprimeRouterTester::mockReceivePacketType(Fw::ComPacket::ComPacketType pack
|
||||
const FwPacketDescriptorType descriptorType = packetType;
|
||||
U8 data[sizeof descriptorType];
|
||||
Fw::Buffer buffer(data, sizeof(data));
|
||||
auto esb = buffer.getSerializer();
|
||||
Fw::SerializeStatus status = esb.serialize(descriptorType);
|
||||
ComCfg::FrameContext nullContext;
|
||||
Fw::SerializeStatus status = buffer.getSerializer().serialize(descriptorType);
|
||||
FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
|
||||
Fw::Buffer nullContext;
|
||||
this->invoke_to_dataIn(0, buffer, nullContext);
|
||||
}
|
||||
|
||||
|
||||
@ -50,12 +50,12 @@ void FrameAccumulator ::cleanup() {
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void FrameAccumulator ::dataIn_handler(FwIndexType portNum, Fw::Buffer& buffer, const Drv::RecvStatus& status) {
|
||||
void FrameAccumulator ::dataIn_handler(FwIndexType portNum, Fw::Buffer& buffer) {
|
||||
// Check whether there is data to process
|
||||
if (status.e == Drv::RecvStatus::RECV_OK) {
|
||||
// There is: process the data
|
||||
if (buffer.isValid()) {
|
||||
this->processBuffer(buffer);
|
||||
}
|
||||
// TODO: rework the uplink deallocation logic to use the bufferReturn chaining pattern
|
||||
// Deallocate the buffer
|
||||
this->bufferDeallocate_out(0, buffer);
|
||||
}
|
||||
@ -135,8 +135,8 @@ void FrameAccumulator ::processRing() {
|
||||
FW_ASSERT(m_inRing.get_allocated_size() == remaining - size_out,
|
||||
static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
|
||||
static_cast<FwAssertArgType>(remaining), static_cast<FwAssertArgType>(size_out));
|
||||
Fw::Buffer nullContext;
|
||||
this->frameOut_out(0, buffer, nullContext);
|
||||
ComCfg::FrameContext context;
|
||||
this->frameOut_out(0, buffer, context);
|
||||
} else {
|
||||
// No buffer is available, we need to exit and try again later
|
||||
this->log_WARNING_HI_NoBufferAvailable();
|
||||
|
||||
@ -50,8 +50,7 @@ class FrameAccumulator final : public FrameAccumulatorComponentBase {
|
||||
//!
|
||||
//! Receives raw data from a ByteStreamDriver, ComStub, or other buffer producing component
|
||||
void dataIn_handler(FwIndexType portNum, //!< The port number
|
||||
Fw::Buffer& recvBuffer,
|
||||
const Drv::RecvStatus& recvStatus) override;
|
||||
Fw::Buffer& recvBuffer) override;
|
||||
|
||||
PRIVATE:
|
||||
//! \brief process raw buffer
|
||||
|
||||
@ -66,7 +66,7 @@ The `Svc::FrameAccumulator` component is used in the uplink stack of many refere
|
||||
classDiagram
|
||||
class FrameAccumulator~PassiveComponent~ {
|
||||
+ void configure(FrameDetector& detector, FwEnumStoreType allocationId, Fw::MemAllocator& allocator, FwSizeType store_size)
|
||||
+ void dataIn_handler(FwIndexType portNum, Fw::Buffer& recvBuffer, const Drv::RecvStatus& recvStatus)
|
||||
+ void dataIn_handler(FwIndexType portNum, Fw::Buffer& recvBuffer, const Drv::ByteStreamStatus& recvStatus)
|
||||
+ void processBuffer(Fw::Buffer& buffer)
|
||||
+ void processRing()
|
||||
}
|
||||
@ -86,6 +86,6 @@ SVC-FRAME-ACCUMULATOR-004 | `Svc::FrameAccumulator` shall accept byte buffers co
|
||||
| Kind | Name | Type | Description |
|
||||
|---|---|---|---|
|
||||
| `guarded input` | dataIn | `Drv.ByteStreamRecv` | Receives raw data from a ByteStreamDriver, ComStub, or other buffer producing component |
|
||||
| `output` | frameOut | `Fw.DataWithContext` | Port for sending an extracted frame out |
|
||||
| `output` | frameOut | `Svc.ComDataWithContext` | Port for sending an extracted frame out |
|
||||
| `output` | bufferAllocate | `Fw.BufferGet` | Port for allocating buffer to hold extracted frame |
|
||||
| `output`| bufferDeallocate | `Fw.BufferSend` | Port for deallocating buffers received on dataIn. |
|
||||
|
||||
@ -40,7 +40,7 @@ void FrameAccumulatorTester ::testFrameDetected() {
|
||||
// Set the mock detector to report success of size_out = buffer_size
|
||||
this->mockDetector.set_next_result(FrameDetector::Status::FRAME_DETECTED, buffer_size);
|
||||
// Receive the buffer on dataIn
|
||||
this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK);
|
||||
this->invoke_to_dataIn(0, buffer);
|
||||
// Checks
|
||||
ASSERT_from_bufferDeallocate_SIZE(1); // input buffer was deallocated
|
||||
ASSERT_from_frameOut_SIZE(1); // frame was sent
|
||||
@ -56,7 +56,7 @@ void FrameAccumulatorTester ::testMoreDataNeeded() {
|
||||
// Set the mock detector to report more data needed
|
||||
this->mockDetector.set_next_result(FrameDetector::Status::MORE_DATA_NEEDED, buffer_size + 1);
|
||||
// Receive the buffer on dataIn
|
||||
this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK);
|
||||
this->invoke_to_dataIn(0, buffer);
|
||||
// Checks
|
||||
ASSERT_from_bufferDeallocate_SIZE(1); // input buffer was deallocated
|
||||
ASSERT_from_frameOut_SIZE(0); // frame was not sent (waiting on more data)
|
||||
@ -71,7 +71,7 @@ void FrameAccumulatorTester ::testNoFrameDetected() {
|
||||
// Set the mock detector
|
||||
this->mockDetector.set_next_result(FrameDetector::Status::NO_FRAME_DETECTED, 0);
|
||||
// Receive the buffer on dataIn
|
||||
this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK);
|
||||
this->invoke_to_dataIn(0, buffer);
|
||||
// Checks
|
||||
ASSERT_from_bufferDeallocate_SIZE(1); // input buffer was deallocated
|
||||
ASSERT_from_frameOut_SIZE(0); // No frame was sent out
|
||||
@ -84,7 +84,7 @@ void FrameAccumulatorTester ::testReceiveZeroSizeBuffer() {
|
||||
U8 data[1] = {0};
|
||||
Fw::Buffer buffer(data, 0);
|
||||
// Receive the buffer on dataIn
|
||||
this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK);
|
||||
this->invoke_to_dataIn(0, buffer);
|
||||
// Checks
|
||||
ASSERT_from_bufferDeallocate_SIZE(1); // input buffer was deallocated
|
||||
ASSERT_from_frameOut_SIZE(0); // No frame was sent out
|
||||
@ -102,11 +102,11 @@ void FrameAccumulatorTester ::testAccumulateTwoBuffers() {
|
||||
|
||||
this->mockDetector.set_next_result(FrameDetector::Status::MORE_DATA_NEEDED, buffer2_size);
|
||||
// Receive the buffer on dataIn
|
||||
this->invoke_to_dataIn(0, buffer1, Drv::RecvStatus::RECV_OK);
|
||||
this->invoke_to_dataIn(0, buffer1);
|
||||
// Next result is detection of a full frame, size = buffer1_size + buffer2_size
|
||||
this->mockDetector.set_next_result(FrameDetector::Status::FRAME_DETECTED, buffer1_size + buffer2_size );
|
||||
// Receive the buffer on dataIn
|
||||
this->invoke_to_dataIn(0, buffer2, Drv::RecvStatus::RECV_OK);
|
||||
this->invoke_to_dataIn(0, buffer2);
|
||||
|
||||
// Checks
|
||||
ASSERT_from_bufferDeallocate_SIZE(2); // both input buffers deallocated
|
||||
@ -171,7 +171,7 @@ void FrameAccumulatorTester ::mockAccumulateFullFrame(U32& frame_size, U32& buff
|
||||
buffer.setSize(buffer_size);
|
||||
// Detector reports MORE_DATA_NEEDED and size needed bigger than accumulated size so far
|
||||
this->mockDetector.set_next_result(FrameDetector::Status::MORE_DATA_NEEDED, accumulated_size + 1);
|
||||
this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK);
|
||||
this->invoke_to_dataIn(0, buffer);
|
||||
}
|
||||
|
||||
// Send last buffer with FRAME_DETECTED
|
||||
@ -181,7 +181,7 @@ void FrameAccumulatorTester ::mockAccumulateFullFrame(U32& frame_size, U32& buff
|
||||
// Send last buffer with finally FRAME_DETECTED and total accumulated + last buffer
|
||||
this->mockDetector.set_next_result(FrameDetector::Status::FRAME_DETECTED, accumulated_size);
|
||||
// Receive the last buffer on dataIn
|
||||
this->invoke_to_dataIn(0, buffer, Drv::RecvStatus::RECV_OK);
|
||||
this->invoke_to_dataIn(0, buffer);
|
||||
frame_size = accumulated_size;
|
||||
buffer_count = iters + 1;
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ TEST(FprimeFrameDetector, TestBufferTooSmall) {
|
||||
|
||||
// Anything smaller than the size of header + trailer is invalid
|
||||
U32 minimum_valid_size =
|
||||
FprimeProtocol::FrameHeader::SERIALIZED_SIZE + FprimeProtocol::FrameTrailer::SERIALIZED_SIZE;
|
||||
Svc::FprimeProtocol::FrameHeader::SERIALIZED_SIZE + Svc::FprimeProtocol::FrameTrailer::SERIALIZED_SIZE;
|
||||
U32 invalid_size = STest::Random::lowerUpper(1, minimum_valid_size - 1);
|
||||
// Set the circular buffer to hold data of invalid size
|
||||
circular_buffer.serialize(buffer, invalid_size);
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
####
|
||||
# F prime CMakeLists.txt:
|
||||
#
|
||||
# SOURCE_FILES: combined list of source and autocoding files
|
||||
# MOD_DEPS: (optional) module dependencies
|
||||
#
|
||||
# Note: using PROJECT_NAME as EXECUTABLE_NAME
|
||||
####
|
||||
set(SOURCE_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/Framer.fpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/Framer.cpp"
|
||||
)
|
||||
|
||||
set(MOD_DEPS
|
||||
Svc/FramingProtocol
|
||||
)
|
||||
|
||||
register_fprime_module()
|
||||
|
||||
#### UTS ###
|
||||
set(UT_SOURCE_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/Framer.fpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/test/ut/FramerTester.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/test/ut/FramerTestMain.cpp"
|
||||
)
|
||||
register_fprime_ut()
|
||||
@ -1,87 +0,0 @@
|
||||
// ======================================================================
|
||||
// \title Framer.cpp
|
||||
// \author mstarch
|
||||
// \brief cpp file for Framer component implementation class
|
||||
//
|
||||
// \copyright
|
||||
// Copyright 2009-2022, by the California Institute of Technology.
|
||||
// ALL RIGHTS RESERVED. United States Government Sponsorship
|
||||
// acknowledged.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include <Fw/FPrimeBasicTypes.hpp>
|
||||
#include <Svc/Framer/Framer.hpp>
|
||||
#include "Fw/Logger/Logger.hpp"
|
||||
#include "Utils/Hash/Hash.hpp"
|
||||
|
||||
namespace Svc {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction, initialization, and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
Framer ::Framer(const char* const compName)
|
||||
: FramerComponentBase(compName), FramingProtocolInterface(), m_protocol(nullptr), m_frame_sent(false) {}
|
||||
|
||||
Framer ::~Framer() {}
|
||||
|
||||
void Framer ::setup(FramingProtocol& protocol) {
|
||||
FW_ASSERT(this->m_protocol == nullptr);
|
||||
this->m_protocol = &protocol;
|
||||
protocol.setup(*this);
|
||||
}
|
||||
|
||||
void Framer ::handle_framing(const U8* const data, const U32 size, Fw::ComPacket::ComPacketType packet_type) {
|
||||
FW_ASSERT(this->m_protocol != nullptr);
|
||||
this->m_frame_sent = false; // Clear the flag to detect if frame was sent
|
||||
this->m_protocol->frame(data, size, packet_type);
|
||||
// If no frame was sent, Framer has the obligation to report success
|
||||
if (this->isConnected_comStatusOut_OutputPort(0) && (!this->m_frame_sent)) {
|
||||
Fw::Success status = Fw::Success::SUCCESS;
|
||||
this->comStatusOut_out(0, status);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Framer ::comIn_handler(const FwIndexType portNum, Fw::ComBuffer& data, U32 context) {
|
||||
FW_ASSERT(data.getBuffLength() < std::numeric_limits<U32>::max(), static_cast<FwAssertArgType>(data.getBuffLength()));
|
||||
this->handle_framing(data.getBuffAddr(), static_cast<U32>(data.getBuffLength()), Fw::ComPacket::FW_PACKET_UNKNOWN);
|
||||
}
|
||||
|
||||
void Framer ::bufferIn_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
|
||||
this->handle_framing(fwBuffer.getData(), fwBuffer.getSize(), Fw::ComPacket::FW_PACKET_FILE);
|
||||
// Deallocate the buffer after it was processed by the framing protocol
|
||||
this->bufferDeallocate_out(0, fwBuffer);
|
||||
}
|
||||
|
||||
void Framer ::comStatusIn_handler(const FwIndexType portNum, Fw::Success& condition) {
|
||||
if (this->isConnected_comStatusOut_OutputPort(portNum)) {
|
||||
this->comStatusOut_out(portNum, condition);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Framing protocol implementations
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Framer ::send(Fw::Buffer& outgoing) {
|
||||
FW_ASSERT(!this->m_frame_sent); // Prevent multiple sends per-packet
|
||||
const Drv::SendStatus sendStatus = this->framedOut_out(0, outgoing);
|
||||
if (sendStatus.e != Drv::SendStatus::SEND_OK) {
|
||||
// Note: if there is a data sending problem, an EVR likely wouldn't
|
||||
// make it down. Log the issue in hopes that
|
||||
// someone will see it.
|
||||
Fw::Logger::log("[ERROR] Failed to send framed data: %d\n", sendStatus.e);
|
||||
}
|
||||
this->m_frame_sent = true; // A frame was sent
|
||||
}
|
||||
|
||||
Fw::Buffer Framer ::allocate(const U32 size) {
|
||||
return this->framedAllocate_out(0, size);
|
||||
}
|
||||
|
||||
} // end namespace Svc
|
||||
@ -1,50 +0,0 @@
|
||||
module Svc {
|
||||
|
||||
@ A component for framing input for transmission to the ground
|
||||
passive component Framer {
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Receiving packets
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Port for receiving data packets of any type stored in statically-sized
|
||||
@ Fw::Com buffers
|
||||
guarded input port comIn: Fw.Com
|
||||
|
||||
@ Port for receiving file packets stored in dynamically-sized
|
||||
@ Fw::Buffer objects
|
||||
guarded input port bufferIn: Fw.BufferSend
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Allocation and deallocation of buffers
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Port for deallocating buffers received on bufferIn, after
|
||||
@ copying packet data to the frame buffer
|
||||
output port bufferDeallocate: Fw.BufferSend
|
||||
|
||||
@ Port for allocating buffers to hold framed data
|
||||
output port framedAllocate: Fw.BufferGet
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Sending frame data
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Port for sending buffers containing framed data. Ownership of the
|
||||
@ buffer passes to the receiver.
|
||||
output port framedOut: Drv.ByteStreamSend
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Handling of of ready signals
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Port receiving the general status from the downstream component
|
||||
@ indicating it is ready or not-ready for more input
|
||||
sync input port comStatusIn: Fw.SuccessCondition
|
||||
|
||||
@ Port receiving indicating the status of framer for receiving more data
|
||||
output port comStatusOut: Fw.SuccessCondition
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,113 +0,0 @@
|
||||
// ======================================================================
|
||||
// \title Framer.hpp
|
||||
// \author mstarch, bocchino
|
||||
// \brief hpp file for Framer component implementation class
|
||||
//
|
||||
// \copyright
|
||||
// Copyright 2009-2022, by the California Institute of Technology.
|
||||
// ALL RIGHTS RESERVED. United States Government Sponsorship
|
||||
// acknowledged.
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#ifndef Svc_Framer_HPP
|
||||
#define Svc_Framer_HPP
|
||||
|
||||
#include "Svc/Framer/FramerComponentAc.hpp"
|
||||
#include "Svc/FramingProtocol/FramingProtocol.hpp"
|
||||
#include "Svc/FramingProtocol/FramingProtocolInterface.hpp"
|
||||
|
||||
namespace Svc {
|
||||
/**
|
||||
* \brief Generic framing component using FramingProtocol implementation for actual framing
|
||||
*
|
||||
* Framing component used to take Com and File packets and frame serialize them using a
|
||||
* framing protocol specified in a FramingProtocol instance. The instance must be supplied
|
||||
* using the `setup` method.
|
||||
*
|
||||
* Using this component, projects can implement and supply a fresh FramingProtocol implementation
|
||||
* without changing the reference topology.
|
||||
*/
|
||||
class Framer final : public FramerComponentBase, public FramingProtocolInterface {
|
||||
public:
|
||||
// ----------------------------------------------------------------------
|
||||
// Construction, initialization, and destruction
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Construct object Framer
|
||||
//!
|
||||
Framer(const char* const compName /*!< The component name*/
|
||||
);
|
||||
|
||||
//! \brief Setup this component with a supplied framing protocol
|
||||
//!
|
||||
void setup(FramingProtocol& protocol /*!< Protocol used in framing */);
|
||||
|
||||
//! Destroy object Framer
|
||||
//!
|
||||
~Framer();
|
||||
|
||||
PRIVATE:
|
||||
// ----------------------------------------------------------------------
|
||||
// Handler implementations for user-defined typed input ports
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! Handler implementation for comIn
|
||||
//!
|
||||
void comIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::ComBuffer& data, /*!< Buffer containing packet data*/
|
||||
U32 context /*!< Call context value; meaning chosen by user*/
|
||||
);
|
||||
|
||||
//! Handler implementation for bufferIn
|
||||
//!
|
||||
void bufferIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Buffer& fwBuffer /*!< The buffer*/
|
||||
);
|
||||
|
||||
//! Handler implementation for comStatusIn
|
||||
//!
|
||||
void comStatusIn_handler(const FwIndexType portNum, /*!< The port number*/
|
||||
Fw::Success& condition /*!< The condition*/);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Implementation of FramingProtocolInterface
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! \brief Allocation callback used to request memory for the framer
|
||||
//!
|
||||
//! Method used by the FramingProtocol to allocate memory for the framed buffer. Framing
|
||||
//! typically adds tokens on the beginning and end of the raw data so it must allocate new space
|
||||
//! to place those and a copy of the data in.
|
||||
//!
|
||||
//! \param size: size of allocation
|
||||
//! \return Fw::Buffer containing allocation to write into
|
||||
Fw::Buffer allocate(const U32 size);
|
||||
|
||||
//! Send implementation
|
||||
//!
|
||||
void send(Fw::Buffer& outgoing //!< The buffer to send
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper functions
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! \brief helper function to handle framing of the raw data
|
||||
//!
|
||||
void handle_framing(const U8* const data, const U32 size, Fw::ComPacket::ComPacketType packet_type);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Member variables
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
//! The FramingProtocol implementation
|
||||
FramingProtocol* m_protocol;
|
||||
|
||||
//! Flag determining if at least one frame was sent during framing
|
||||
bool m_frame_sent;
|
||||
};
|
||||
|
||||
} // end namespace Svc
|
||||
|
||||
#endif
|
||||
@ -1 +0,0 @@
|
||||
DATA_FOLDER=top/
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 107 KiB |
@ -1,48 +0,0 @@
|
||||
{
|
||||
"columns" : [
|
||||
[
|
||||
{
|
||||
"instanceName" : "eventLogger",
|
||||
"inputPorts" : [],
|
||||
"outputPorts" : [
|
||||
{
|
||||
"name" : "PktSend",
|
||||
"portNumbers" : [
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"instanceName" : "framer",
|
||||
"inputPorts" : [
|
||||
{
|
||||
"name" : "comIn",
|
||||
"portNumbers" : [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputPorts" : []
|
||||
}
|
||||
]
|
||||
],
|
||||
"connections" : [
|
||||
[
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 33 KiB |
@ -1,6 +0,0 @@
|
||||
eventLogger
|
||||
PktSend
|
||||
0
|
||||
framer
|
||||
comIn
|
||||
0
|
||||
@ -1,109 +0,0 @@
|
||||
{
|
||||
"columns" : [
|
||||
[
|
||||
{
|
||||
"instanceName" : "framer",
|
||||
"inputPorts" : [],
|
||||
"outputPorts" : [
|
||||
{
|
||||
"name" : "framedOut",
|
||||
"portNumbers" : [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "framedAllocate",
|
||||
"portNumbers" : [
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"instanceName" : "comm",
|
||||
"inputPorts" : [
|
||||
{
|
||||
"name" : "send",
|
||||
"portNumbers" : [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputPorts" : [
|
||||
{
|
||||
"name" : "deallocate",
|
||||
"portNumbers" : [
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"instanceName" : "buffMgr",
|
||||
"inputPorts" : [
|
||||
{
|
||||
"name" : "bufferSendIn",
|
||||
"portNumbers" : [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "bufferGetCallee",
|
||||
"portNumbers" : [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputPorts" : []
|
||||
}
|
||||
]
|
||||
],
|
||||
"connections" : [
|
||||
[
|
||||
[
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0
|
||||
],
|
||||
[
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
[
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user