diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 916f63bb68..4ff049f1c7 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -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 diff --git a/.github/actions/spelling/patterns.txt b/.github/actions/spelling/patterns.txt index 2ef3ce12ee..8d5bad22f7 100644 --- a/.github/actions/spelling/patterns.txt +++ b/.github/actions/spelling/patterns.txt @@ -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+\( diff --git a/Drv/ByteStreamDriverModel/ByteStreamDriverModel.fpp b/Drv/ByteStreamDriverModel/ByteStreamDriverModel.fpp index 208a53f280..932d2af3b1 100644 --- a/Drv/ByteStreamDriverModel/ByteStreamDriverModel.fpp +++ b/Drv/ByteStreamDriverModel/ByteStreamDriverModel.fpp @@ -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() + } diff --git a/Drv/ByteStreamDriverModel/changed-symbols.txt b/Drv/ByteStreamDriverModel/changed-symbols.txt deleted file mode 100644 index 00f248412c..0000000000 --- a/Drv/ByteStreamDriverModel/changed-symbols.txt +++ /dev/null @@ -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 diff --git a/Drv/ByteStreamDriverModel/docs/sdd.md b/Drv/ByteStreamDriverModel/docs/sdd.md index b06f371ec4..304d1a807c 100644 --- a/Drv/ByteStreamDriverModel/docs/sdd.md +++ b/Drv/ByteStreamDriverModel/docs/sdd.md @@ -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 ![Callback](./img/canvas-callback.png) 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 - -![Poll](./img/canvas-poll.png) - -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 ![classdiagram](./img/class_diagram.png) @@ -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 | diff --git a/Drv/CMakeLists.txt b/Drv/CMakeLists.txt index 61d8d67725..275ba86321 100644 --- a/Drv/CMakeLists.txt +++ b/Drv/CMakeLists.txt @@ -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/") diff --git a/Drv/Interfaces/ByteStreamDriverInterface.fppi b/Drv/Interfaces/ByteStreamDriverInterface.fppi index 3fb46c4100..e2a22f149b 100644 --- a/Drv/Interfaces/ByteStreamDriverInterface.fppi +++ b/Drv/Interfaces/ByteStreamDriverInterface.fppi @@ -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 diff --git a/Drv/LinuxUartDriver/LinuxUartDriver.cpp b/Drv/LinuxUartDriver/LinuxUartDriver.cpp index 8587b06bfe..8e304e7765 100644 --- a/Drv/LinuxUartDriver/LinuxUartDriver.cpp +++ b/Drv/LinuxUartDriver/LinuxUartDriver.cpp @@ -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(serBuffer.getSize()) <= std::numeric_limits::max(), @@ -307,28 +307,25 @@ Drv::SendStatus LinuxUartDriver ::send_handler(const FwIndexType portNum, Fw::Bu if (-1 == stat || static_cast(stat) != xferSize) { Fw::LogStringArg _arg = this->m_device; this->log_WARNING_HI_WriteError(_arg, static_cast(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(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(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 } diff --git a/Drv/LinuxUartDriver/LinuxUartDriver.fpp b/Drv/LinuxUartDriver/LinuxUartDriver.fpp index efca43e03e..38b8078172 100644 --- a/Drv/LinuxUartDriver/LinuxUartDriver.fpp +++ b/Drv/LinuxUartDriver/LinuxUartDriver.fpp @@ -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 # ---------------------------------------------------------------------- diff --git a/Drv/LinuxUartDriver/LinuxUartDriver.hpp b/Drv/LinuxUartDriver/LinuxUartDriver.hpp index 513b63230a..7e98ba0ff2 100644 --- a/Drv/LinuxUartDriver/LinuxUartDriver.hpp +++ b/Drv/LinuxUartDriver/LinuxUartDriver.hpp @@ -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); diff --git a/Drv/StreamCrossover/CMakeLists.txt b/Drv/StreamCrossover/CMakeLists.txt deleted file mode 100644 index 731896bbc2..0000000000 --- a/Drv/StreamCrossover/CMakeLists.txt +++ /dev/null @@ -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() diff --git a/Drv/StreamCrossover/StreamCrossover.cpp b/Drv/StreamCrossover/StreamCrossover.cpp deleted file mode 100644 index 5793801758..0000000000 --- a/Drv/StreamCrossover/StreamCrossover.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// ====================================================================== -// \title StreamCrossover.cpp -// \author ethanchee -// \brief cpp file for StreamCrossover component implementation class -// ====================================================================== - - -#include -#include - -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 diff --git a/Drv/StreamCrossover/StreamCrossover.fpp b/Drv/StreamCrossover/StreamCrossover.fpp deleted file mode 100644 index 286aaf3d09..0000000000 --- a/Drv/StreamCrossover/StreamCrossover.fpp +++ /dev/null @@ -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 - - } - -} diff --git a/Drv/StreamCrossover/StreamCrossover.hpp b/Drv/StreamCrossover/StreamCrossover.hpp deleted file mode 100644 index 740084999c..0000000000 --- a/Drv/StreamCrossover/StreamCrossover.hpp +++ /dev/null @@ -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 diff --git a/Drv/StreamCrossover/docs/sdd.md b/Drv/StreamCrossover/docs/sdd.md deleted file mode 100644 index f97c656785..0000000000 --- a/Drv/StreamCrossover/docs/sdd.md +++ /dev/null @@ -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 | diff --git a/Drv/StreamCrossover/test/ut/StreamCrossoverTestMain.cpp b/Drv/StreamCrossover/test/ut/StreamCrossoverTestMain.cpp deleted file mode 100644 index a4523c48a9..0000000000 --- a/Drv/StreamCrossover/test/ut/StreamCrossoverTestMain.cpp +++ /dev/null @@ -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(); -} diff --git a/Drv/StreamCrossover/test/ut/StreamCrossoverTester.cpp b/Drv/StreamCrossover/test/ut/StreamCrossoverTester.cpp deleted file mode 100644 index 9c98ee4dc5..0000000000 --- a/Drv/StreamCrossover/test/ut/StreamCrossoverTester.cpp +++ /dev/null @@ -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 diff --git a/Drv/StreamCrossover/test/ut/StreamCrossoverTester.hpp b/Drv/StreamCrossover/test/ut/StreamCrossoverTester.hpp deleted file mode 100644 index e7c03783cb..0000000000 --- a/Drv/StreamCrossover/test/ut/StreamCrossoverTester.hpp +++ /dev/null @@ -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 diff --git a/Drv/TcpClient/TcpClient.fpp b/Drv/TcpClient/TcpClient.fpp index 7e80cc1244..e9ad3152e0 100644 --- a/Drv/TcpClient/TcpClient.fpp +++ b/Drv/TcpClient/TcpClient.fpp @@ -2,10 +2,9 @@ module Drv { passive component TcpClient { include "../Interfaces/ByteStreamDriverInterface.fppi" - - output port allocate: Fw.BufferGet - output port deallocate: Fw.BufferSend + @ Allocation for received data + output port allocate: Fw.BufferGet } } diff --git a/Drv/TcpClient/TcpClientComponentImpl.cpp b/Drv/TcpClient/TcpClientComponentImpl.cpp index 67acb45e8b..1d74886bb0 100644 --- a/Drv/TcpClient/TcpClientComponentImpl.cpp +++ b/Drv/TcpClient/TcpClientComponentImpl.cpp @@ -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 diff --git a/Drv/TcpClient/TcpClientComponentImpl.hpp b/Drv/TcpClient/TcpClientComponentImpl.hpp index 6a947cae50..becf5968d2 100644 --- a/Drv/TcpClient/TcpClientComponentImpl.hpp +++ b/Drv/TcpClient/TcpClientComponentImpl.hpp @@ -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 diff --git a/Drv/TcpClient/docs/sdd.md b/Drv/TcpClient/docs/sdd.md index cf1ab6caf7..8904e7c2b7 100644 --- a/Drv/TcpClient/docs/sdd.md +++ b/Drv/TcpClient/docs/sdd.md @@ -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** - -![Callback](../../ByteStreamDriverModel/docs/img/canvas-callback.png) - -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 diff --git a/Drv/TcpClient/test/ut/TcpClientTester.cpp b/Drv/TcpClient/test/ut/TcpClientTester.cpp index a7edc8d5bc..dd9ae9b741 100644 --- a/Drv/TcpClient/test/ut/TcpClientTester.cpp +++ b/Drv/TcpClient/test/ut/TcpClientTester.cpp @@ -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 diff --git a/Drv/TcpClient/test/ut/TcpClientTester.hpp b/Drv/TcpClient/test/ut/TcpClientTester.hpp index 1dadad6974..392d0c9b4d 100644 --- a/Drv/TcpClient/test/ut/TcpClientTester.hpp +++ b/Drv/TcpClient/test/ut/TcpClientTester.hpp @@ -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: diff --git a/Drv/TcpServer/TcpServer.fpp b/Drv/TcpServer/TcpServer.fpp index 91f59afcdd..49fdfcc248 100644 --- a/Drv/TcpServer/TcpServer.fpp +++ b/Drv/TcpServer/TcpServer.fpp @@ -2,10 +2,9 @@ module Drv { passive component TcpServer { include "../Interfaces/ByteStreamDriverInterface.fppi" - - output port allocate: Fw.BufferGet - output port deallocate: Fw.BufferSend + @ Allocation for received data + output port allocate: Fw.BufferGet } } diff --git a/Drv/TcpServer/TcpServerComponentImpl.cpp b/Drv/TcpServer/TcpServerComponentImpl.cpp index fae78e8b00..3e42151f93 100644 --- a/Drv/TcpServer/TcpServerComponentImpl.cpp +++ b/Drv/TcpServer/TcpServerComponentImpl.cpp @@ -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 diff --git a/Drv/TcpServer/TcpServerComponentImpl.hpp b/Drv/TcpServer/TcpServerComponentImpl.hpp index 8ad2de84b0..b6d500b8b6 100644 --- a/Drv/TcpServer/TcpServerComponentImpl.hpp +++ b/Drv/TcpServer/TcpServerComponentImpl.hpp @@ -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 diff --git a/Drv/TcpServer/docs/sdd.md b/Drv/TcpServer/docs/sdd.md index 93a9512749..5e494990c0 100644 --- a/Drv/TcpServer/docs/sdd.md +++ b/Drv/TcpServer/docs/sdd.md @@ -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** - -![Callback](../../ByteStreamDriverModel/docs/img/canvas-callback.png) - -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 diff --git a/Drv/TcpServer/test/ut/TcpServerTester.cpp b/Drv/TcpServer/test/ut/TcpServerTester.cpp index 6865131592..05052d4318 100644 --- a/Drv/TcpServer/test/ut/TcpServerTester.cpp +++ b/Drv/TcpServer/test/ut/TcpServerTester.cpp @@ -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 diff --git a/Drv/TcpServer/test/ut/TcpServerTester.hpp b/Drv/TcpServer/test/ut/TcpServerTester.hpp index 7c2ea216ee..3d749da620 100644 --- a/Drv/TcpServer/test/ut/TcpServerTester.hpp +++ b/Drv/TcpServer/test/ut/TcpServerTester.hpp @@ -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: diff --git a/Drv/Udp/Udp.fpp b/Drv/Udp/Udp.fpp index 08f27cf829..7d49930350 100644 --- a/Drv/Udp/Udp.fpp +++ b/Drv/Udp/Udp.fpp @@ -5,7 +5,5 @@ module Drv { output port allocate: Fw.BufferGet - output port deallocate: Fw.BufferSend - } } diff --git a/Drv/Udp/UdpComponentImpl.cpp b/Drv/Udp/UdpComponentImpl.cpp index adc1e0e42d..109b29f642 100644 --- a/Drv/Udp/UdpComponentImpl.cpp +++ b/Drv/Udp/UdpComponentImpl.cpp @@ -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 diff --git a/Drv/Udp/UdpComponentImpl.hpp b/Drv/Udp/UdpComponentImpl.hpp index bd1f444c06..38ced2d473 100644 --- a/Drv/Udp/UdpComponentImpl.hpp +++ b/Drv/Udp/UdpComponentImpl.hpp @@ -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 diff --git a/Drv/Udp/docs/sdd.md b/Drv/Udp/docs/sdd.md index 04b111183f..b066251007 100644 --- a/Drv/Udp/docs/sdd.md +++ b/Drv/Udp/docs/sdd.md @@ -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** - -![Callback](../../ByteStreamDriverModel/docs/img/canvas-callback.png) - -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 diff --git a/Drv/Udp/test/ut/UdpTester.cpp b/Drv/Udp/test/ut/UdpTester.cpp index 647cafc9ca..460b27e59d 100644 --- a/Drv/Udp/test/ut/UdpTester.cpp +++ b/Drv/Udp/test/ut/UdpTester.cpp @@ -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 diff --git a/Drv/Udp/test/ut/UdpTester.hpp b/Drv/Udp/test/ut/UdpTester.hpp index 04171ac694..85ea3ec124 100644 --- a/Drv/Udp/test/ut/UdpTester.hpp +++ b/Drv/Udp/test/ut/UdpTester.hpp @@ -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: diff --git a/Fw/Buffer/Buffer.fpp b/Fw/Buffer/Buffer.fpp index fab0b95895..48dd549caf 100644 --- a/Fw/Buffer/Buffer.fpp +++ b/Fw/Buffer/Buffer.fpp @@ -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) } diff --git a/RPI/RpiDemo/RpiDemo.fpp b/RPI/RpiDemo/RpiDemo.fpp index 01bee01e73..2e32f26824 100644 --- a/RPI/RpiDemo/RpiDemo.fpp +++ b/RPI/RpiDemo/RpiDemo.fpp @@ -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 diff --git a/RPI/RpiDemo/RpiDemoComponentImpl.cpp b/RPI/RpiDemo/RpiDemoComponentImpl.cpp index e68f15fe08..c7cef32cf0 100644 --- a/RPI/RpiDemo/RpiDemoComponentImpl.cpp +++ b/RPI/RpiDemo/RpiDemoComponentImpl.cpp @@ -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(serBuffer.getData()); @@ -142,16 +142,18 @@ namespace RPI { Fw::Buffer txt; txt.setSize(text.length()); txt.setData(reinterpret_cast(const_cast(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(buffer.getData())); + this->log_ACTIVITY_HI_RD_UartMsgOut(arg); + } + } + void RpiDemoComponentImpl :: RD_SetGpio_cmdHandler( const FwOpcodeType opCode, diff --git a/RPI/RpiDemo/RpiDemoComponentImpl.hpp b/RPI/RpiDemo/RpiDemoComponentImpl.hpp index 5c25e65936..ffb0ebe736 100644 --- a/RPI/RpiDemo/RpiDemoComponentImpl.hpp +++ b/RPI/RpiDemo/RpiDemoComponentImpl.hpp @@ -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: // ---------------------------------------------------------------------- diff --git a/RPI/Top/RPITopologyDefs.hpp b/RPI/Top/RPITopologyDefs.hpp index 8d291469fb..ca65f6d634 100644 --- a/RPI/Top/RPITopologyDefs.hpp +++ b/RPI/Top/RPITopologyDefs.hpp @@ -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 diff --git a/RPI/Top/instances.fpp b/RPI/Top/instances.fpp index c1eb6de51b..5ce91205a1 100644 --- a/RPI/Top/instances.fpp +++ b/RPI/Top/instances.fpp @@ -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 + + } diff --git a/RPI/Top/topology.fpp b/RPI/Top/topology.fpp index 0620fd0463..750e3b20e1 100644 --- a/RPI/Top/topology.fpp +++ b/RPI/Top/topology.fpp @@ -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 diff --git a/Ref/Top/CMakeLists.txt b/Ref/Top/CMakeLists.txt index 777d727bc3..62ac01e376 100644 --- a/Ref/Top/CMakeLists.txt +++ b/Ref/Top/CMakeLists.txt @@ -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() diff --git a/Ref/Top/RefPackets.fppi b/Ref/Top/RefPackets.fppi index f3dc54ab99..526400ffd7 100644 --- a/Ref/Top/RefPackets.fppi +++ b/Ref/Top/RefPackets.fppi @@ -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 } diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp index b4fbfb212e..b65d442bd0 100644 --- a/Ref/Top/RefTopology.cpp +++ b/Ref/Top/RefTopology.cpp @@ -14,8 +14,8 @@ // Necessary project-specified types #include #include -#include #include +#include // Used for 1Hz synthetic cycling #include @@ -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); diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index a98146b22b..0e2e9f45c6 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -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 diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index aafba6dac8..78884e00c0 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -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 } diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index d898343b27..36eff8549c 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -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 diff --git a/Svc/CMakeLists.txt b/Svc/CMakeLists.txt index 9bd505bd6a..6ebfef10f1 100644 --- a/Svc/CMakeLists.txt +++ b/Svc/CMakeLists.txt @@ -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. diff --git a/Svc/ComQueue/ComQueue.cpp b/Svc/ComQueue/ComQueue.cpp index 3a40f43e83..4607c2565b 100644 --- a/Svc/ComQueue/ComQueue.cpp +++ b/Svc/ComQueue/ComQueue.cpp @@ -6,6 +6,7 @@ #include #include +#include #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(portNum)); (void)this->enqueue(portNum, QueueType::COM_QUEUE, reinterpret_cast(&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::max() - COM_PORT_COUNT > portNum); const FwIndexType queueNum = static_cast(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(portNum)); FW_ASSERT(queueNum < TOTAL_PORT_COUNT); - bool status = + bool success = this->enqueue(queueNum, QueueType::BUFFER_QUEUE, reinterpret_cast(&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::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(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(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(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(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(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(&comBuffer), sizeof(comBuffer)); - this->sendComBuffer(comBuffer); + this->sendComBuffer(comBuffer, entry.index); } else { Fw::Buffer buffer; queue.dequeue(reinterpret_cast(&buffer), sizeof(buffer)); - this->sendBuffer(buffer); + this->sendBuffer(buffer, entry.index); } // Update the throttle and the index that was just sent diff --git a/Svc/ComQueue/ComQueue.fpp b/Svc/ComQueue/ComQueue.fpp index a45ec081a5..ad85de3f70 100644 --- a/Svc/ComQueue/ComQueue.fpp +++ b/Svc/ComQueue/ComQueue.fpp @@ -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 diff --git a/Svc/ComQueue/ComQueue.hpp b/Svc/ComQueue/ComQueue.hpp index f960379ccb..92d35ffa4e 100644 --- a/Svc/ComQueue/ComQueue.hpp +++ b/Svc/ComQueue/ComQueue.hpp @@ -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::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 /*! [!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 diff --git a/Svc/ComQueue/test/ut/ComQueueTestMain.cpp b/Svc/ComQueue/test/ut/ComQueueTestMain.cpp index d5266d696f..0506b57740 100644 --- a/Svc/ComQueue/test/ut/ComQueueTestMain.cpp +++ b/Svc/ComQueue/test/ut/ComQueueTestMain.cpp @@ -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(); diff --git a/Svc/ComQueue/test/ut/ComQueueTester.cpp b/Svc/ComQueue/test/ut/ComQueueTester.cpp index 2d00bd8953..540973879e 100644 --- a/Svc/ComQueue/test/ut/ComQueueTester.cpp +++ b/Svc/ComQueue/test/ut/ComQueueTester.cpp @@ -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 diff --git a/Svc/ComQueue/test/ut/ComQueueTester.hpp b/Svc/ComQueue/test/ut/ComQueueTester.hpp index 9895bb8c0a..78b2e42d52 100644 --- a/Svc/ComQueue/test/ut/ComQueueTester.hpp +++ b/Svc/ComQueue/test/ut/ComQueueTester.hpp @@ -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 diff --git a/Svc/ComStub/CMakeLists.txt b/Svc/ComStub/CMakeLists.txt index c0da3c9a86..551d0fce89 100644 --- a/Svc/ComStub/CMakeLists.txt +++ b/Svc/ComStub/CMakeLists.txt @@ -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() diff --git a/Svc/ComStub/ComStub.cpp b/Svc/ComStub/ComStub.cpp index eb9713439b..d05b919008 100644 --- a/Svc/ComStub/ComStub.cpp +++ b/Svc/ComStub/ComStub.cpp @@ -5,6 +5,7 @@ // ====================================================================== #include +#include #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 diff --git a/Svc/ComStub/ComStub.fpp b/Svc/ComStub/ComStub.fpp index dd66cb973c..57d5eab852 100644 --- a/Svc/ComStub/ComStub.fpp +++ b/Svc/ComStub/ComStub.fpp @@ -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 } -} \ No newline at end of file +} diff --git a/Svc/ComStub/ComStub.hpp b/Svc/ComStub/ComStub.hpp index 95d672881c..7db4ba0c5d 100644 --- a/Svc/ComStub/ComStub.hpp +++ b/Svc/ComStub/ComStub.hpp @@ -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 diff --git a/Svc/ComStub/docs/sdd.md b/Svc/ComStub/docs/sdd.md index 242115e52b..fe1c157ef5 100644 --- a/Svc/ComStub/docs/sdd.md +++ b/Svc/ComStub/docs/sdd.md @@ -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 diff --git a/Svc/ComStub/test/ut/ComStubTestMain.cpp b/Svc/ComStub/test/ut/ComStubTestMain.cpp index 0125faf0ef..80531e4a56 100644 --- a/Svc/ComStub/test/ut/ComStubTestMain.cpp +++ b/Svc/ComStub/test/ut/ComStubTestMain.cpp @@ -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(); diff --git a/Svc/ComStub/test/ut/ComStubTester.cpp b/Svc/ComStub/test/ut/ComStubTester.cpp index 114876c59a..a86a5e0df1 100644 --- a/Svc/ComStub/test/ut/ComStubTester.cpp +++ b/Svc/ComStub/test/ut/ComStubTester.cpp @@ -7,12 +7,6 @@ #include "ComStubTester.hpp" #include -#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(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(i + 1)); + ASSERT_from_drvDataOut(static_cast(i), buffers[i]); } + ASSERT_from_drvDataOut_SIZE(static_cast(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(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(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 diff --git a/Svc/ComStub/test/ut/ComStubTester.hpp b/Svc/ComStub/test/ut/ComStubTester.hpp index f609ebe7be..a4b00d0226 100644 --- a/Svc/ComStub/test/ut/ComStubTester.hpp +++ b/Svc/ComStub/test/ut/ComStubTester.hpp @@ -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 }; diff --git a/Svc/FprimeDeframer/FprimeDeframer.cpp b/Svc/FprimeDeframer/FprimeDeframer.cpp index cdf0d1122d..0622e9c0d3 100644 --- a/Svc/FprimeDeframer/FprimeDeframer.cpp +++ b/Svc/FprimeDeframer/FprimeDeframer.cpp @@ -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(); diff --git a/Svc/FprimeDeframer/FprimeDeframer.hpp b/Svc/FprimeDeframer/FprimeDeframer.hpp index 887c5ac3fb..f6313777c7 100644 --- a/Svc/FprimeDeframer/FprimeDeframer.hpp +++ b/Svc/FprimeDeframer/FprimeDeframer.hpp @@ -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 diff --git a/Svc/FprimeDeframer/docs/sdd.md b/Svc/FprimeDeframer/docs/sdd.md index ac3d49c9d9..b8ed3ec52c 100644 --- a/Svc/FprimeDeframer/docs/sdd.md +++ b/Svc/FprimeDeframer/docs/sdd.md @@ -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 | diff --git a/Svc/FprimeDeframer/test/ut/FprimeDeframerTester.cpp b/Svc/FprimeDeframer/test/ut/FprimeDeframerTester.cpp index 076c63273f..c56b6a4b45 100644 --- a/Svc/FprimeDeframer/test/ut/FprimeDeframerTester.cpp +++ b/Svc/FprimeDeframer/test/ut/FprimeDeframerTester.cpp @@ -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(size)); this->invoke_to_framedIn(0, buffer, nullContext); } diff --git a/Svc/FprimeFramer/CMakeLists.txt b/Svc/FprimeFramer/CMakeLists.txt new file mode 100644 index 0000000000..65185e2c51 --- /dev/null +++ b/Svc/FprimeFramer/CMakeLists.txt @@ -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() diff --git a/Svc/FprimeFramer/FprimeFramer.cpp b/Svc/FprimeFramer/FprimeFramer.cpp new file mode 100644 index 0000000000..e599362257 --- /dev/null +++ b/Svc/FprimeFramer/FprimeFramer.cpp @@ -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::max(), static_cast(frameSize)); + FW_ASSERT(frameSize <= std::numeric_limits::max(), static_cast(frameSize)); + + // Allocate frame buffer + Fw::Buffer frameBuffer = this->bufferAllocate_out(0, static_cast(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 diff --git a/Svc/FprimeFramer/FprimeFramer.fpp b/Svc/FprimeFramer/FprimeFramer.fpp new file mode 100644 index 0000000000..d8b991c555 --- /dev/null +++ b/Svc/FprimeFramer/FprimeFramer.fpp @@ -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 + + } +} diff --git a/Svc/FprimeFramer/FprimeFramer.hpp b/Svc/FprimeFramer/FprimeFramer.hpp new file mode 100644 index 0000000000..e501d5cefa --- /dev/null +++ b/Svc/FprimeFramer/FprimeFramer.hpp @@ -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 diff --git a/Svc/FprimeFramer/docs/img/framer-topology.png b/Svc/FprimeFramer/docs/img/framer-topology.png new file mode 100644 index 0000000000..c67c69029b Binary files /dev/null and b/Svc/FprimeFramer/docs/img/framer-topology.png differ diff --git a/Svc/FprimeFramer/docs/sdd.md b/Svc/FprimeFramer/docs/sdd.md new file mode 100644 index 0000000000..a059be4523 --- /dev/null +++ b/Svc/FprimeFramer/docs/sdd.md @@ -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. + +![./img/framer-topology.png](./img/framer-topology.png) + +## 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 | + diff --git a/Svc/FprimeFramer/test/ut/FprimeFramerTestMain.cpp b/Svc/FprimeFramer/test/ut/FprimeFramerTestMain.cpp new file mode 100644 index 0000000000..e1acc1be26 --- /dev/null +++ b/Svc/FprimeFramer/test/ut/FprimeFramerTestMain.cpp @@ -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(); +} diff --git a/Svc/FprimeFramer/test/ut/FprimeFramerTester.cpp b/Svc/FprimeFramer/test/ut/FprimeFramerTester.cpp new file mode 100644 index 0000000000..deb66f81e9 --- /dev/null +++ b/Svc/FprimeFramer/test/ut/FprimeFramerTester.cpp @@ -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(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 diff --git a/Svc/FprimeFramer/test/ut/FprimeFramerTester.hpp b/Svc/FprimeFramer/test/ut/FprimeFramerTester.hpp new file mode 100644 index 0000000000..64a7dc9c9c --- /dev/null +++ b/Svc/FprimeFramer/test/ut/FprimeFramerTester.hpp @@ -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 diff --git a/Svc/FprimeProtocol/FprimeProtocol.fpp b/Svc/FprimeProtocol/FprimeProtocol.fpp index c70126e891..d4e667d64d 100644 --- a/Svc/FprimeProtocol/FprimeProtocol.fpp +++ b/Svc/FprimeProtocol/FprimeProtocol.fpp @@ -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 { } } +} diff --git a/Svc/FprimeRouter/FprimeRouter.cpp b/Svc/FprimeRouter/FprimeRouter.cpp index f0e0900ea0..660c1b8e3c 100644 --- a/Svc/FprimeRouter/FprimeRouter.cpp +++ b/Svc/FprimeRouter/FprimeRouter.cpp @@ -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; } diff --git a/Svc/FprimeRouter/FprimeRouter.fpp b/Svc/FprimeRouter/FprimeRouter.fpp index 0053cbebf6..baff261a9d 100644 --- a/Svc/FprimeRouter/FprimeRouter.fpp +++ b/Svc/FprimeRouter/FprimeRouter.fpp @@ -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 diff --git a/Svc/FprimeRouter/FprimeRouter.hpp b/Svc/FprimeRouter/FprimeRouter.hpp index eaeb3d5c14..cb3bed691a 100644 --- a/Svc/FprimeRouter/FprimeRouter.hpp +++ b/Svc/FprimeRouter/FprimeRouter.hpp @@ -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 diff --git a/Svc/FprimeRouter/docs/sdd.md b/Svc/FprimeRouter/docs/sdd.md index 96f01b35e9..d4bfe76089 100644 --- a/Svc/FprimeRouter/docs/sdd.md +++ b/Svc/FprimeRouter/docs/sdd.md @@ -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 diff --git a/Svc/FprimeRouter/test/ut/FprimeRouterTester.cpp b/Svc/FprimeRouter/test/ut/FprimeRouterTester.cpp index 77dccbc51e..34aac1ce3c 100644 --- a/Svc/FprimeRouter/test/ut/FprimeRouterTester.cpp +++ b/Svc/FprimeRouter/test/ut/FprimeRouterTester.cpp @@ -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); } diff --git a/Svc/FrameAccumulator/FrameAccumulator.cpp b/Svc/FrameAccumulator/FrameAccumulator.cpp index 22cd8830ef..7243b51ebb 100644 --- a/Svc/FrameAccumulator/FrameAccumulator.cpp +++ b/Svc/FrameAccumulator/FrameAccumulator.cpp @@ -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(m_inRing.get_allocated_size()), static_cast(remaining), static_cast(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(); diff --git a/Svc/FrameAccumulator/FrameAccumulator.hpp b/Svc/FrameAccumulator/FrameAccumulator.hpp index 8dab6c6f03..9635ec4a42 100644 --- a/Svc/FrameAccumulator/FrameAccumulator.hpp +++ b/Svc/FrameAccumulator/FrameAccumulator.hpp @@ -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 diff --git a/Svc/FrameAccumulator/docs/sdd.md b/Svc/FrameAccumulator/docs/sdd.md index 34d7df34fa..34e24c1ae6 100644 --- a/Svc/FrameAccumulator/docs/sdd.md +++ b/Svc/FrameAccumulator/docs/sdd.md @@ -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. | diff --git a/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp b/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp index 2c826b54ec..b0b96c2b14 100644 --- a/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp +++ b/Svc/FrameAccumulator/test/ut/FrameAccumulatorTester.cpp @@ -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; } diff --git a/Svc/FrameAccumulator/test/ut/detectors/FprimeFrameDetectorTestMain.cpp b/Svc/FrameAccumulator/test/ut/detectors/FprimeFrameDetectorTestMain.cpp index a445fc3d5e..d79ae88311 100644 --- a/Svc/FrameAccumulator/test/ut/detectors/FprimeFrameDetectorTestMain.cpp +++ b/Svc/FrameAccumulator/test/ut/detectors/FprimeFrameDetectorTestMain.cpp @@ -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); diff --git a/Svc/Framer/CMakeLists.txt b/Svc/Framer/CMakeLists.txt deleted file mode 100644 index 0bf69bfc36..0000000000 --- a/Svc/Framer/CMakeLists.txt +++ /dev/null @@ -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() diff --git a/Svc/Framer/Framer.cpp b/Svc/Framer/Framer.cpp deleted file mode 100644 index 88ce684e2f..0000000000 --- a/Svc/Framer/Framer.cpp +++ /dev/null @@ -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 -#include -#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::max(), static_cast(data.getBuffLength())); - this->handle_framing(data.getBuffAddr(), static_cast(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 diff --git a/Svc/Framer/Framer.fpp b/Svc/Framer/Framer.fpp deleted file mode 100644 index b71ea772ba..0000000000 --- a/Svc/Framer/Framer.fpp +++ /dev/null @@ -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 - - } - -} diff --git a/Svc/Framer/Framer.hpp b/Svc/Framer/Framer.hpp deleted file mode 100644 index e1a9453840..0000000000 --- a/Svc/Framer/Framer.hpp +++ /dev/null @@ -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 diff --git a/Svc/Framer/docs/img/.fpv-env b/Svc/Framer/docs/img/.fpv-env deleted file mode 100644 index ff60caacf4..0000000000 --- a/Svc/Framer/docs/img/.fpv-env +++ /dev/null @@ -1 +0,0 @@ -DATA_FOLDER=top/ diff --git a/Svc/Framer/docs/img/Framer.png b/Svc/Framer/docs/img/Framer.png deleted file mode 100644 index bf86d6b493..0000000000 Binary files a/Svc/Framer/docs/img/Framer.png and /dev/null differ diff --git a/Svc/Framer/docs/img/top/event.json b/Svc/Framer/docs/img/top/event.json deleted file mode 100644 index 5267fe8c9f..0000000000 --- a/Svc/Framer/docs/img/top/event.json +++ /dev/null @@ -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 - ] - ] - ] -} diff --git a/Svc/Framer/docs/img/top/event.png b/Svc/Framer/docs/img/top/event.png deleted file mode 100644 index f585289878..0000000000 Binary files a/Svc/Framer/docs/img/top/event.png and /dev/null differ diff --git a/Svc/Framer/docs/img/top/event.txt b/Svc/Framer/docs/img/top/event.txt deleted file mode 100644 index 01cc5916c8..0000000000 --- a/Svc/Framer/docs/img/top/event.txt +++ /dev/null @@ -1,6 +0,0 @@ -eventLogger -PktSend -0 -framer -comIn -0 diff --git a/Svc/Framer/docs/img/top/framed.json b/Svc/Framer/docs/img/top/framed.json deleted file mode 100644 index 300491b337..0000000000 --- a/Svc/Framer/docs/img/top/framed.json +++ /dev/null @@ -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 - ] - ] - ] -} diff --git a/Svc/Framer/docs/img/top/framed.png b/Svc/Framer/docs/img/top/framed.png deleted file mode 100644 index 7813c271fb..0000000000 Binary files a/Svc/Framer/docs/img/top/framed.png and /dev/null differ diff --git a/Svc/Framer/docs/img/top/framed.txt b/Svc/Framer/docs/img/top/framed.txt deleted file mode 100644 index 3dabc9a9f3..0000000000 --- a/Svc/Framer/docs/img/top/framed.txt +++ /dev/null @@ -1,20 +0,0 @@ -framer -framedAllocate -0 -buffMgr -bufferGetCallee -0 - -comm -deallocate -0 -buffMgr -bufferSendIn -0 - -framer -framedOut -0 -comm -send -0 diff --git a/Svc/Framer/docs/img/top/framer-file.json b/Svc/Framer/docs/img/top/framer-file.json deleted file mode 100644 index 1c35a02fbd..0000000000 --- a/Svc/Framer/docs/img/top/framer-file.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "columns" : [ - [ - { - "instanceName" : "fileDownlink", - "inputPorts" : [ - { - "name" : "bufferReturn", - "portNumbers" : [ - 0 - ] - } - ], - "outputPorts" : [ - { - "name" : "bufferSendOut", - "portNumbers" : [ - 0 - ] - } - ] - } - ], - [ - { - "instanceName" : "framer", - "inputPorts" : [ - { - "name" : "bufferIn", - "portNumbers" : [ - 0 - ] - } - ], - "outputPorts" : [ - { - "name" : "bufferDeallocate", - "portNumbers" : [ - 0 - ] - } - ] - } - ] - ], - "connections" : [ - [ - [ - 0, - 0, - 0, - 0 - ], - [ - 1, - 0, - 0, - 0 - ] - ], - [ - [ - 1, - 0, - 0, - 0 - ], - [ - 0, - 0, - 0, - 0 - ] - ] - ] -} diff --git a/Svc/Framer/docs/img/top/framer-file.png b/Svc/Framer/docs/img/top/framer-file.png deleted file mode 100644 index 7d284aa0d8..0000000000 Binary files a/Svc/Framer/docs/img/top/framer-file.png and /dev/null differ diff --git a/Svc/Framer/docs/img/top/framer-file.txt b/Svc/Framer/docs/img/top/framer-file.txt deleted file mode 100644 index 400fc3049f..0000000000 --- a/Svc/Framer/docs/img/top/framer-file.txt +++ /dev/null @@ -1,13 +0,0 @@ -fileDownlink -bufferSendOut -0 -framer -bufferIn -0 - -framer -bufferDeallocate -0 -fileDownlink -bufferReturn -0 diff --git a/Svc/Framer/docs/img/top/hub.json b/Svc/Framer/docs/img/top/hub.json deleted file mode 100644 index 17d0fec967..0000000000 --- a/Svc/Framer/docs/img/top/hub.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "columns" : [ - [ - { - "instanceName" : "hub", - "inputPorts" : [], - "outputPorts" : [ - { - "name" : "portOut", - "portNumbers" : [ - 0, - 1 - ] - } - ] - } - ], - [ - { - "instanceName" : "framer", - "inputPorts" : [ - { - "name" : "comIn", - "portNumbers" : [ - 0 - ] - } - ], - "outputPorts" : [] - } - ] - ], - "connections" : [ - [ - [ - 0, - 0, - 0, - 0 - ], - [ - 1, - 0, - 0, - 0 - ] - ], - [ - [ - 0, - 0, - 0, - 1 - ], - [ - 1, - 0, - 0, - 0 - ] - ] - ] -} diff --git a/Svc/Framer/docs/img/top/hub.png b/Svc/Framer/docs/img/top/hub.png deleted file mode 100644 index 510126bc9d..0000000000 Binary files a/Svc/Framer/docs/img/top/hub.png and /dev/null differ diff --git a/Svc/Framer/docs/img/top/hub.txt b/Svc/Framer/docs/img/top/hub.txt deleted file mode 100644 index 87a7c7d508..0000000000 --- a/Svc/Framer/docs/img/top/hub.txt +++ /dev/null @@ -1,13 +0,0 @@ -hub -portOut -0 -framer -comIn -0 - -hub -portOut -1 -framer -comIn -0 diff --git a/Svc/Framer/docs/img/top/tlm.json b/Svc/Framer/docs/img/top/tlm.json deleted file mode 100644 index 2a172d5de5..0000000000 --- a/Svc/Framer/docs/img/top/tlm.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "columns" : [ - [ - { - "instanceName" : "chanTlm", - "inputPorts" : [], - "outputPorts" : [ - { - "name" : "PktSend", - "portNumbers" : [ - 0 - ] - } - ] - } - ], - [ - { - "instanceName" : "framer", - "inputPorts" : [ - { - "name" : "comIn", - "portNumbers" : [ - 0 - ] - } - ], - "outputPorts" : [] - } - ] - ], - "connections" : [ - [ - [ - 0, - 0, - 0, - 0 - ], - [ - 1, - 0, - 0, - 0 - ] - ] - ] -} diff --git a/Svc/Framer/docs/img/top/tlm.png b/Svc/Framer/docs/img/top/tlm.png deleted file mode 100644 index 66e234a24e..0000000000 Binary files a/Svc/Framer/docs/img/top/tlm.png and /dev/null differ diff --git a/Svc/Framer/docs/img/top/tlm.txt b/Svc/Framer/docs/img/top/tlm.txt deleted file mode 100644 index 11ed0e9ff0..0000000000 --- a/Svc/Framer/docs/img/top/tlm.txt +++ /dev/null @@ -1,6 +0,0 @@ -chanTlm -PktSend -0 -framer -comIn -0 diff --git a/Svc/Framer/docs/sdd.md b/Svc/Framer/docs/sdd.md deleted file mode 100644 index 42e3e771bc..0000000000 --- a/Svc/Framer/docs/sdd.md +++ /dev/null @@ -1,313 +0,0 @@ -# Svc::Framer (Passive Component) - -## 1. Introduction - -`Svc::Framer` is a passive component. -It is part of the standard path for F Prime data downlink. -It accepts data packets from service layer components, for example -instances of [`Svc::TlmChan`](../../TlmChan/docs/sdd.md), -[`Svc::ActiveLogger`](../../ActiveLogger/docs/sdd.md), -or [`Svc::FileDownlink`](../../FileDownlink/docs/sdd.md). -For each packet _P_ received, it wraps _P_ in a frame _F_ -and sends _F_ to a byte stream driver that downlinks frames, -for example, [`Drv::TcpClient`](../../../Drv/TcpClient/docs/sdd.md). - -When instantiating `Framer`, you must provide an implementation -of [`Svc::FramingProtocol`](../../FramingProtocol/docs/sdd.md). -This implementation specifies exactly what is -in each frame; typically it is a frame header, a data packet, and a hash value. -You can use the standard F Prime downlink protocol implementation. -This implementation works with the F Prime ground data system (GDS). - -`Svc::Framer` is designed to act alongside instances of the -[communication adapter interface](../../../docs/reference/communication-adapter-interface.md). In order -to work well with communication adapters, `Svc::Framer` implements the framer status -[protocol](../../../docs/reference/communication-adapter-interface.md#framer-status-protocol). - -## 2. Assumptions - -1. For any deployment _D_ that uses an instance _I_ of `Framer`, the - framing protocol used with _I_ matches the downlink protocol of - any ground system that receives frames from _I_. - -## 3. Requirements - -| Requirement | Description | Rationale | Verification Method | -|------------------|----------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------| -| SVC-FRAMER-001 | `Svc::Framer` shall accept data packets of any type stored in `Fw::Com` buffers. | `Svc::ActiveLogger` and `Svc::ChanTlm` emit packets as `Fw::Com` buffers. | Unit test | -| SVC-FRAMER-002 | `Svc::Framer` shall accept file packets stored in `Fw::Buffer` objects. | `Svc::FileDownlink` emits packets as `Fw::Buffer` objects. | Unit test | -| SVC-FRAMER-003 | `Svc::Framer` shall use an instance of `Svc::FramingProtocol`, supplied when the component is instantiated, to wrap packets in frames. | The purpose of `Svc::Framer` is to frame data packets. Using the `Svc::FramingProtocol` interface allows the same Framer component to operate with different protocols. | Unit test | -| SVC-FRAMER-004 | `Svc::Framer` shall emit a status of `Fw::Success::SUCCESS` when no framed packets were sent in response to incoming buffer. | `Svc::Framer` implements the framer status protocol. | Unit Test | -| SVC-FRAMER-005 | `Svc::Framer` shall forward `Fw::Success` status messages received | `Svc::Framer` implements the framer status protocol. | Unit Test | - -## 4. Design - -### 4.1. Component Diagram - -The diagram below shows the `Framer` component. - -![Framer Component](./img/Framer.png) - -### 4.2. Ports - -| Kind | Name | Port Type | Usage | -|-----------------|--------------------|-----------------------|---------------------------------------------------------------------------------------------------| -| `guarded input` | `comIn` | `Fw.Com` | Port for receiving data packets of any type stored in statically-sized Fw::Com buffers | -| `guarded input` | `bufferIn` | `Fw.BufferSend` | Port for receiving file packets stored in dynamically-sized Fw::Buffer objects | -| `guarded input` | `comStatusIn` | `Fw.SuccessCondition` | Port for receiving status of last send for implementing communication adapter interface protocol | -| `output` | `bufferDeallocate` | `Fw.BufferSend` | Port for deallocating buffers received on bufferIn, after copying packet data to the frame buffer | -| `output` | `framedAllocate` | `Fw.BufferGet` | Port for allocating buffers to hold framed data | -| `output` | `framedOut` | `Drv.ByteStreamSend` | Port for sending buffers containing framed data. Ownership of the buffer passes to the receiver. | -| `output` | `comStatusOut` | `Fw.SuccessCondition` | Port for sending communication adapter interface protocol status messages | - - -### 4.3. Derived Classes - -`Framer` is derived from `FramerComponentBase` as usual. -It is also derived (via C++ multiple inheritance) from -[`Svc::FramingProtocolInterface`](../../FramingProtocol/docs/sdd.md). -The multiple inheritance makes the `Framer` instance into the -instance of `Svc::FramingProtocolInterface` that is required -to use `Svc::FramingProtocol`. -See below for a description of how `Framer` implements -`FramingProtocolInterface`. - -Here is a class diagram for `Framer`: - -```mermaid -classDiagram - ObjBase <|-- PassiveComponentBase - PassiveComponentBase <|-- FramerComponentBase - FramerComponentBase <|-- Framer - FramingProtocolInterface <|-- Framer -``` - -### 4.4. State - -`Framer` maintains the following state: - -1. `m_protocol`: A pointer to the implementation of `FramingProtocol` - used for framing. - -### 4.5. Header File Configuration - -None. - - -### 4.6. Runtime Setup - -To set up an instance of `Framer`, you do the following: - -1. Call the constructor and the `init` method in the usual way -for an F Prime passive component. - -1. Call the `setup` method, passing in an instance _P_ of `Svc::FramingProtocol`. -The `setup` method does the following: - - 1. Store a pointer to _P_ in `m_protocol`. - - 1. Pass `*this` into the setup method for _P_. - As noted above, `*this` - is the instance of `Svc::FramingProtocolInterface` - used by _P_. - -For an example of setting up a `Framer` instance, see the -`downlink` instance in [`Ref/Top/instances.fpp`](../../../Ref/Top/instances.fpp). - -### 4.7. Port Handlers - -#### 4.7.1. comIn - -The `comIn` port handler receive a reference to an `Fw::Com` buffer _B_ -and an integer context value. -It calls the `frame` method of `m_protocol`, passing in the -address and length of _B_ and the packet type -`Fw::ComPacket::FW_PACKET_UNKNOWN`. - -#### 4.7.2. bufferIn - -The `bufferIn` port handler receives a reference to an `Fw::Buffer` -object _B_. -It calls the `frame` method of `m_protocol`, passing in the -data address and size of _B_ and the packet type -`Fw::ComPacket::FW_PACKET_FILE`. - -#### 4.7.2. comStatusIn - -The `comStatusIn` port handler receives com status messages and forwards them out `comStatusOut`. - - -### 4.8. Implementation of Svc::FramingProtocolInterface - - -#### 4.8.1. allocate - -The implementation of `allocate` invokes `framedAllocate`. - - -#### 4.8.2. send - -The implementation of `send` takes a reference to an `Fw::Buffer` -_B_ representing framed data and does the following: - -1. Invoke `framedOut`, passing in _B_ as the argument. - -1. Check the return status of the invocation. -If the return status is not `Drv::SendStatus::SEND_OK`, then -use `Fw::Logger::log` to log an error message. -Don't send an event report in this case, because downlink is -apparently not working. - -## 5. Ground Interface - -None. - -If an error occurs, `Framer` writes to the system log. -The rationale is that if something is wrong with the framing, then -downlink of events is unlikely to work. - -## 6. Example Uses - - -### 6.1. Topology Diagrams - -The following topology diagrams show how to connect `Svc::Framer` -to a telemetry database, an event collector, a file downlink component, -and a byte stream driver. -The diagrams use the following instances: - -* `comm`: An instance of -[`Drv::ByteStreamDriverModel`](../../../Drv/ByteStreamDriverModel/docs/sdd.md), for example -[`Drv::TcpClient`](../../../Drv/TcpClient/docs/sdd.md). - -* `buffMgr`: An instance of [`Svc::BufferManager`](../../BufferManager/docs/sdd.md) - -* `fileDownlink`: An instance of [`Svc::FileDownlink`](../../FileDownlink/docs/sdd.md). - -* `framer`: An instance of `Svc::Framer`. - -* `chanTlm`: An instance of [`Svc::TlmChan`](../../TlmChan/docs/sdd.md). - -* `eventLogger`: An instance of [`Svc::ActiveLogger`](../../ActiveLogger/docs/sdd.md). - -**Topology 1: Telemetry packets:** - -![tlm](img/top/tlm.png) - -The `chanTlm` instance sends telemetry packets to the `framer` instance. - -**Topology 2: Event packets:** - -![event](img/top/event.png) - -The `eventLogger` instance sends event packets to the `framer` instance. - -**Topology 3: File packets:** - -![file](img/top/framer-file.png) - -The `fileDownlink` instance sends a sequence of file packets, -representing a complete file, to the `framer` instance. -The sending happens in the following sequence: - -1. `fileDownlink` sends a buffer _PB_ containing a file packet. - -1. `framer` receives and processes _PB_. -When it is done, it returns _PB_ to `fileDownlink`. - -1. Upon receipt of _PB_, if another file packet is available, -`fileDownlink` sends it. - -Exchanging the buffer controls the rate at which -`fileDownlink` sends file packets. -It ensures that the rate does not exceed the rate at which `framer` -can handle the packets. - -**Topology 4: Framed data:** - -![framed](img/top/framed.png) - -`framer` allocates frame buffers from `buffMgr`. -It sends buffers containing frames to `comm`. -`comm` processes the buffers and sends them to -`buffMgr` for deallocation. - -### 6.2. Sequence Diagrams - -In the following diagrams, open vertical rectangles represent threads. -Vertical dashed lines represent component code. -Solid horizontal arrows represent synchronous port invocations, and open -horizontal arrows represent asynchronous port invocations. - -These diagrams assume that, in the -implementation of `Svc::FramingProtocol` -passed in at initialization, -each downlink frame contains a single packet. -This is a common use case; for example, the F Prime standard downlink protocol -is implemented this way. - -#### 6.2.1. Sending a Telemetry Packet - -The following diagram shows what happens when `chanTlm` -sends a telemetry packet to `framer`. - -```mermaid -sequenceDiagram - activate chanTlm - chanTlm->>framer: Send telemetry packet P [comIn] - framer->>buffMgr: Allocate frame buffer B [framedAllocate] - buffMgr-->>framer: Return B - framer->>framer: Frame P into B - framer-)comm: Send B [framedOut] - comm->>comm: Downlink frame - comm->>buffMgr: Deallocate B - buffMgr-->>comm: - comm-->>framer: - framer-->>chanTlm: - deactivate chanTlm -``` - -#### 6.2.2. Sending an Event Packet - -The following diagram shows what happens when `eventLogger` -sends an event packet to `framer`. - -```mermaid -sequenceDiagram - activate eventLogger - eventLogger->>framer: Send event packet P [comIn] - framer->>buffMgr: Allocate frame buffer B [framedAllocate] - buffMgr-->>framer: Return B - framer->>framer: Frame P into B - framer-)comm: Send B [framedOut] - comm->>comm: Downlink frame - comm->>buffMgr: Deallocate B - buffMgr-->>comm: - comm-->>framer: - framer-->>eventLogger: - deactivate eventLogger -``` - -#### 6.2.3. Sending a File Packet - -The following diagram shows what happens when `fileDownlink` -sends a file packet to `framer`. - -```mermaid -sequenceDiagram - activate fileDownlink - fileDownlink->>framer: Send file packet buffer PB [bufferIn] - framer->>buffMgr: Allocate frame buffer B [framedAllocate] - buffMgr-->>framer: Return B - framer->>framer: Frame P into B - framer-)comm: Send B [framedOut] - comm->>comm: Downlink frame - comm->>buffMgr: Deallocate B - buffMgr-->>comm: - comm-->>framer: - framer->>fileDownlink: Return PB [bufferDeallocate] - fileDownlink-->>framer: - framer-->>fileDownlink: - deactivate fileDownlink -``` - diff --git a/Svc/Framer/test/ut/FramerTestMain.cpp b/Svc/Framer/test/ut/FramerTestMain.cpp deleted file mode 100644 index b0c0189f9b..0000000000 --- a/Svc/Framer/test/ut/FramerTestMain.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// ---------------------------------------------------------------------- -// TestMain.cpp -// ---------------------------------------------------------------------- - -#include "Fw/Test/UnitTest.hpp" -#include "Os/Console.hpp" -#include "FramerTester.hpp" - -// Enable the console logging provided by Os::Log -Os::Console logger; - -TEST(Nominal, Com) { - COMMENT("Send one Fw::Com buffer to the framer (nominal behavior)"); - REQUIREMENT("SVC-FRAMER-001"); - REQUIREMENT("SVC-FRAMER-003"); - Svc::FramerTester tester; - tester.test_com(); -} - -TEST(Nominal, Buffer) { - COMMENT("Send one Fw::Buffer to the framer (nominal behavior)"); - REQUIREMENT("SVC-FRAMER-002"); - REQUIREMENT("SVC-FRAMER-003"); - Svc::FramerTester tester; - tester.test_buffer(); -} - -TEST(Nominal, ManySends) { - COMMENT("Send several buffers"); - REQUIREMENT("SVC-FRAMER-001"); - REQUIREMENT("SVC-FRAMER-002"); - REQUIREMENT("SVC-FRAMER-003"); - Svc::FramerTester tester; - tester.test_com(27); - tester.test_buffer(27); - tester.test_com(31); - tester.test_buffer(31); -} - -TEST(Nominal, StatusPassThrough) { - COMMENT("Ensure status pass-through"); - REQUIREMENT("SVC-FRAMER-004"); - Svc::FramerTester tester; - tester.test_status_pass_through(); -} - -TEST(Nominal, NoSendStatus) { - COMMENT("Ensure status on no-send"); - REQUIREMENT("SVC-FRAMER-003"); - Svc::FramerTester tester; - tester.test_no_send_status(); -} - -TEST(SendError, Buffer) { - COMMENT("Send one Fw::Buffer to the framer (send error)"); - REQUIREMENT("SVC-FRAMER-002"); - REQUIREMENT("SVC-FRAMER-003"); - Svc::FramerTester tester; - tester.setSendStatus(Drv::SendStatus::SEND_ERROR); - tester.test_buffer(); -} - -TEST(SendError, Com) { - COMMENT("Send one Fw::Com buffer to the framer (send error)"); - REQUIREMENT("SVC-FRAMER-001"); - REQUIREMENT("SVC-FRAMER-003"); - Svc::FramerTester tester; - tester.setSendStatus(Drv::SendStatus::SEND_ERROR); - tester.test_com(); -} - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/Svc/Framer/test/ut/FramerTester.cpp b/Svc/Framer/test/ut/FramerTester.cpp deleted file mode 100644 index 5aeb8d3345..0000000000 --- a/Svc/Framer/test/ut/FramerTester.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// ====================================================================== -// \title Framer.hpp -// \author mstarch, bocchino -// \brief cpp file for Framer test harness implementation class -// -// \copyright -// Copyright 2009-2022, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include "FramerTester.hpp" - -#define INSTANCE 0 -#define MAX_HISTORY_SIZE 1000 - -namespace Svc { - -FramerTester::MockFramer::MockFramer(FramerTester& parent) : m_parent(parent), m_do_not_send(false) {} - -void FramerTester::MockFramer::frame(const U8* const data, const U32 size, Fw::ComPacket::ComPacketType packet_type) { - // When testing without the send case, disable all mock functions - if (!m_do_not_send) { - Fw::Buffer buffer(const_cast(data), size); - m_parent.check_last_buffer(buffer); - Fw::Buffer allocated = m_interface->allocate(size); - m_interface->send(allocated); - } -} - -// ---------------------------------------------------------------------- -// Construction and destruction -// ---------------------------------------------------------------------- - -FramerTester ::FramerTester() - : FramerGTestBase("Tester", MAX_HISTORY_SIZE), - component("Framer"), - m_mock(*this), - m_framed(false), - m_sent(false), - m_returned(false), - m_sendStatus(Drv::SendStatus::SEND_OK) - -{ - this->initComponents(); - this->connectPorts(); - component.setup(this->m_mock); -} - -FramerTester ::~FramerTester() {} - -// ---------------------------------------------------------------------- -// Tests -// ---------------------------------------------------------------------- - -void FramerTester ::test_com(U32 iterations) { - for (U32 i = 0; i < iterations; i++) { - Fw::ComBuffer com; - m_buffer.set(com.getBuffAddr(), static_cast(com.getBuffLength())); - m_framed = false; - m_sent = false; - m_returned = false; - invoke_to_comIn(0, com, 0); - ASSERT_TRUE(m_framed); - if (m_sendStatus == Drv::SendStatus::SEND_OK) { - ASSERT_TRUE(m_sent); - } else { - ASSERT_FALSE(m_sent); - } - ASSERT_FALSE(m_returned); - } -} - -void FramerTester ::test_buffer(U32 iterations) { - for (U32 i = 0; i < iterations; i++) { - Fw::Buffer buffer(new U8[3412], 3412); - m_framed = false; - m_sent = false; - m_returned = false; - m_buffer = buffer; - invoke_to_bufferIn(0, buffer); - ASSERT_TRUE(m_framed); - if (m_sendStatus == Drv::SendStatus::SEND_OK) { - ASSERT_TRUE(m_sent); - } else { - ASSERT_FALSE(m_sent); - } - ASSERT_TRUE(m_returned); - } -} - -void FramerTester ::test_status_pass_through() { - // Check not always success - Fw::Success status = Fw::Success::FAILURE; - invoke_to_comStatusIn(0, status); - ASSERT_from_comStatusOut(0, status); - - // Check a success - status = Fw::Success::SUCCESS; - invoke_to_comStatusIn(0, status); - ASSERT_from_comStatusOut(1, status); -} - -void FramerTester ::test_no_send_status() { - Fw::Success status = Fw::Success::SUCCESS; - m_mock.m_do_not_send = true; - // Send com buffer and check no send and a status - Fw::ComBuffer com; - invoke_to_comIn(0, com, 0); - ASSERT_from_framedOut_SIZE(0); - ASSERT_from_comStatusOut(0, status); - - Fw::Buffer buffer(new U8[3412], 3412); - invoke_to_bufferIn(0, buffer); - ASSERT_from_framedOut_SIZE(0); - ASSERT_from_comStatusOut(0, status); - clearFromPortHistory(); - - // Make sure it still does pass-through - test_status_pass_through(); -} - -void FramerTester ::check_last_buffer(Fw::Buffer buffer) { - ASSERT_EQ(buffer, m_buffer); -} - -// ---------------------------------------------------------------------- -// Handlers for typed from ports -// ---------------------------------------------------------------------- - -void FramerTester ::from_bufferDeallocate_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) { - this->pushFromPortEntry_bufferDeallocate(fwBuffer); - m_returned = true; - delete[] fwBuffer.getData(); -} - -Fw::Buffer FramerTester ::from_framedAllocate_handler(const FwIndexType portNum, U32 size) { - this->pushFromPortEntry_framedAllocate(size); - Fw::Buffer buffer(new U8[size], size); - m_buffer = buffer; - return buffer; -} - -Drv::SendStatus FramerTester ::from_framedOut_handler(const FwIndexType portNum, Fw::Buffer& sendBuffer) { - this->pushFromPortEntry_framedOut(sendBuffer); - this->check_last_buffer(sendBuffer); - delete[] sendBuffer.getData(); - m_framed = true; - if (m_sendStatus == Drv::SendStatus::SEND_OK) { - m_sent = true; - } - return m_sendStatus; -} - -void FramerTester ::from_comStatusOut_handler(const FwIndexType portNum, Fw::Success& condition) { - this->pushFromPortEntry_comStatusOut(condition); -} - -// ---------------------------------------------------------------------- -// Helper methods -// ---------------------------------------------------------------------- - -void FramerTester ::connectPorts() { - // comIn - this->connect_to_comIn(0, this->component.get_comIn_InputPort(0)); - - // bufferIn - this->connect_to_bufferIn(0, this->component.get_bufferIn_InputPort(0)); - - // bufferDeallocate - this->component.set_bufferDeallocate_OutputPort(0, this->get_from_bufferDeallocate(0)); - - // framedAllocate - this->component.set_framedAllocate_OutputPort(0, this->get_from_framedAllocate(0)); - - // framedOut - this->component.set_framedOut_OutputPort(0, this->get_from_framedOut(0)); - - // comStatusIn - this->connect_to_comStatusIn(0, this->component.get_comStatusIn_InputPort(0)); - - // comStatusOut - this->component.set_comStatusOut_OutputPort(0, this->get_from_comStatusOut(0)); -} - -void FramerTester ::initComponents() { - this->init(); - this->component.init(INSTANCE); -} - -void FramerTester ::setSendStatus(Drv::SendStatus sendStatus) { - m_sendStatus = sendStatus; -} - -} // end namespace Svc diff --git a/Svc/Framer/test/ut/FramerTester.hpp b/Svc/Framer/test/ut/FramerTester.hpp deleted file mode 100644 index 37c2738ef6..0000000000 --- a/Svc/Framer/test/ut/FramerTester.hpp +++ /dev/null @@ -1,157 +0,0 @@ -// ====================================================================== -// \title Framer/test/ut/Tester.hpp -// \author mstarch, bocchino -// \brief hpp file for Framer test harness implementation class -// -// \copyright -// Copyright 2009-2022, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef TESTER_HPP -#define TESTER_HPP - -#include "FramerGTestBase.hpp" -#include "Svc/Framer/Framer.hpp" - -namespace Svc { - - -class FramerTester : public FramerGTestBase { - public: - - // ---------------------------------------------------------------------- - // Types - // ---------------------------------------------------------------------- - - //! Mock framing protocol - class MockFramer : public FramingProtocol { - public: - MockFramer(FramerTester& parent); - void frame( - const U8* const data, - const U32 size, - Fw::ComPacket::ComPacketType packet_type - ); - FramerTester& m_parent; - bool m_do_not_send; - }; - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - public: - - //! Construct object FramerTester - FramerTester(); - - //! Destroy object FramerTester - ~FramerTester(); - - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - //! Test incoming Fw::Com data to the framer - void test_com(U32 iterations = 1); - - //! Test incoming Fw::Buffer data to the framer - void test_buffer(U32 iterations = 1); - - //! Tests statuses pass-through - void test_status_pass_through(); - - //! Tests statuses on no-send - void test_no_send_status(); - - //! Check that buffer is equal to the last buffer allocated - void check_last_buffer(Fw::Buffer buffer); - - private: - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - //! Handler for from_bufferDeallocate - void from_bufferDeallocate_handler( - const FwIndexType portNum, //!< The port number - Fw::Buffer& fwBuffer //!< The buffer - ); - - //! Handler for from_framedAllocate - Fw::Buffer from_framedAllocate_handler( - const FwIndexType portNum, //!< The port number - U32 size //!< The size - ); - - //! Handler for from_framedOut - Drv::SendStatus from_framedOut_handler( - const FwIndexType portNum, //!< The port number - Fw::Buffer& sendBuffer //!< The buffer containing framed data - ); - - //! Handler for from_comStatusOut - //! - void from_comStatusOut_handler( - const FwIndexType portNum, /*!< The port number*/ - Fw::Success &condition /*!< Condition success/failure */ - ); - - public: - - // ---------------------------------------------------------------------- - // Public instance methods - // ---------------------------------------------------------------------- - - //! Set the send status - void setSendStatus(Drv::SendStatus sendStatus); - - private: - - // ---------------------------------------------------------------------- - // Private instance methods - // ---------------------------------------------------------------------- - - //! Connect ports - void connectPorts(); - - //! Initialize components - void initComponents(); - - private: - - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - Framer component; - - //! Buffer for sending unframed data - Fw::Buffer m_buffer; - - //! Mock framing protocol - MockFramer m_mock; - - //! Whether framing succeeded - bool m_framed; - - //! Whether sending succeeded - bool m_sent; - - //! Whether the frame buffer was deallocated - bool m_returned; - - //! Send status for error injection - Drv::SendStatus m_sendStatus; -}; - -} // end namespace Svc - -#endif diff --git a/Svc/Interfaces/ComInterface.fppi b/Svc/Interfaces/ComInterface.fppi index 448345a86a..7d34b8412b 100644 --- a/Svc/Interfaces/ComInterface.fppi +++ b/Svc/Interfaces/ComInterface.fppi @@ -1,8 +1,19 @@ -@ Data coming in from the framing component -sync input port comDataIn: Drv.ByteStreamSend +# ---------------------------------------------------------------------- +# Com Data and Status +# ---------------------------------------------------------------------- -@ Status of the last radio transmission -output port comStatus: Fw.SuccessCondition +@ Data to be sent on the wire (coming in to the component) +sync input port comDataIn: Svc.ComDataWithContext -@ Com data passing back out -output port comDataOut: Drv.ByteStreamRecv \ No newline at end of file +@ Data received from the wire (coming out of the component) +output port comDataOut: Fw.BufferSend + +@ Status of the last transmission +output port comStatusOut: Fw.SuccessCondition + +# ---------------------------------------------------------------------- +# Memory management +# ---------------------------------------------------------------------- + +@ Returning ownership of data that came in on comDataIn +output port dataReturnOut: Svc.ComDataWithContext diff --git a/Svc/Interfaces/DeframerInterface.fppi b/Svc/Interfaces/DeframerInterface.fppi index f32a8e756f..139bf30c54 100644 --- a/Svc/Interfaces/DeframerInterface.fppi +++ b/Svc/Interfaces/DeframerInterface.fppi @@ -1,5 +1,5 @@ @ Port to receive framed data, with optional context -guarded input port framedIn: Fw.DataWithContext +guarded input port framedIn: Svc.ComDataWithContext @ Port to output deframed data, with optional context -output port deframedOut: Fw.DataWithContext +output port deframedOut: Svc.ComDataWithContext diff --git a/Svc/Interfaces/FrameAccumulatorInterface.fppi b/Svc/Interfaces/FrameAccumulatorInterface.fppi index 633991d03c..72f1635e08 100644 --- a/Svc/Interfaces/FrameAccumulatorInterface.fppi +++ b/Svc/Interfaces/FrameAccumulatorInterface.fppi @@ -1,5 +1,5 @@ -@ Receives raw data from a ByteStreamDriver, ComStub, or other buffer producing component -guarded input port dataIn: Drv.ByteStreamRecv +@ Receive raw bytes from a ComInterface (e.g. ComStub) +guarded input port dataIn: Fw.BufferSend @ Port for sending an extracted frame out -output port frameOut: Fw.DataWithContext +output port frameOut: Svc.ComDataWithContext diff --git a/Svc/Interfaces/FramerInterface.fppi b/Svc/Interfaces/FramerInterface.fppi new file mode 100644 index 0000000000..83826e5057 --- /dev/null +++ b/Svc/Interfaces/FramerInterface.fppi @@ -0,0 +1,28 @@ +# ---------------------------------------------------------------------- +# Framing +# ---------------------------------------------------------------------- +@ Port to receive data to frame, in a Fw::Buffer with optional context +sync input port dataIn: Svc.ComDataWithContext + +@ Port to output framed data with optional context +output port dataOut: Svc.ComDataWithContext + +# ---------------------------------------------------------------------- +# Data ownership +# ---------------------------------------------------------------------- +@ Port for returning ownership of the incoming Fw::Buffer to its sender +@ once framing is handled +output port dataReturnOut: Svc.ComDataWithContext + +@ Buffer coming from a deallocate call in a ComDriver component +sync input port dataReturnIn: Svc.ComDataWithContext + +# ---------------------------------------------------------------------- +# Handling of ready signals (ComQueue <-> ComInterface) +# ---------------------------------------------------------------------- +@ 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 diff --git a/Svc/Interfaces/RouterInterface.fppi b/Svc/Interfaces/RouterInterface.fppi index 1f8652613d..dafb91b0bb 100644 --- a/Svc/Interfaces/RouterInterface.fppi +++ b/Svc/Interfaces/RouterInterface.fppi @@ -1,5 +1,5 @@ @ Receiving data (Fw::Buffer) to be routed with optional context to help with routing -sync input port dataIn: Fw.DataWithContext +sync input port dataIn: Svc.ComDataWithContext @ Port for sending file packets as Fw::Buffer (ownership passed to receiver) output port fileOut: Fw.BufferSend diff --git a/Svc/Interfaces/docs/sdd.md b/Svc/Interfaces/docs/sdd.md new file mode 100644 index 0000000000..18549bd19a --- /dev/null +++ b/Svc/Interfaces/docs/sdd.md @@ -0,0 +1,27 @@ +# Svc FPP Interfaces + +The Svc interfaces are a set of `.fppi` files that define FPP interfaces for components to implement. An FPP interface is an FPP file that defines a set of ports. A component that implements an FPP interface must implement handlers for the input ports and has access to the output ports of the interface. + +## Svc/ComInterface + +The `Svc/ComInterface` is an interface for implementing the [Communications Adapter Interface](../../../docs/reference/communication-adapter-interface.md). + +## Svc/DeframerInterface + +The `Svc/DeframerInterface` is an interface for implementing a Deframer component. This interface allows a component to be dropped in the common F´ Uplink stack and implement deframing for a specific communications protocol. The [`Svc::FprimeDeframer`](../../FprimeDeframer/docs/sdd.md) component implements this interface for the [F´ communications protocol](../../FprimeProtocol/docs/sdd.md). + +## Svc/FramerInterface + +The `Svc/FramerInterface` is an interface for implementing the Framer component. This interface allows a component to be dropped in the common F´ Downlink stack and implement framing for a specific communications protocol. The [`Svc::FprimeFramer`](../../FprimeFramer/docs/sdd.md) component implements this interface for the [F´ communications protocol](../../FprimeProtocol/docs/sdd.md). + +## Svc/RouterInterface + +The `Svc/RouterInterface` is an interface for implementing a Router component. This interface allows a component to be dropped in the common F´ Uplink stack and implement routing for a project. The [`Svc::FprimeRouter`](../../FprimeRouter/docs/sdd.md) component implements this interface routing the common F´ packets, as well as passing unknown packets down to another component for further processing. + +## Svc/FrameAccumulatorInterface + +The `Svc/FrameAccumulatorInterface` is an interface for implementing a Frame Accumulator component. This allows a component to be dropped in the common F´ Uplink stack and implement frame accumulation, using any desirable algorithm. The [`Svc::FrameAccumulator`](../../FrameAccumulator/docs/sdd.md) component implements this interface by storing the data in a circular buffer and using a `Svc::FrameDetector` to detect frames in the buffer. + +## Svc/TimeInterface + +The `Svc/TimeInterface` is an interface for implementing a Time provider. A time provider must provide a way for other components to get the current time. The [`Svc::PosixTime`](../../PosixTime/docs/sdd.md) component implements this interface, using common Posix functions to retrieve the current time. diff --git a/Svc/Ports/CMakeLists.txt b/Svc/Ports/CMakeLists.txt new file mode 100644 index 0000000000..82babaada7 --- /dev/null +++ b/Svc/Ports/CMakeLists.txt @@ -0,0 +1,4 @@ +# Module subdirectories +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CommsPorts/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/OsTimeEpoch") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/VersionPorts/") diff --git a/Svc/Ports/CommsPorts/CMakeLists.txt b/Svc/Ports/CommsPorts/CMakeLists.txt new file mode 100644 index 0000000000..dcb347a788 --- /dev/null +++ b/Svc/Ports/CommsPorts/CMakeLists.txt @@ -0,0 +1,9 @@ +#### +# CMakeLists.txt: +# +# Sets up the fprime module build within CMake. +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/CommsPorts.fpp" +) +register_fprime_module() diff --git a/Svc/Ports/CommsPorts/CommsPorts.fpp b/Svc/Ports/CommsPorts/CommsPorts.fpp new file mode 100644 index 0000000000..3b26be1fef --- /dev/null +++ b/Svc/Ports/CommsPorts/CommsPorts.fpp @@ -0,0 +1,13 @@ +##### +# Communications Ports: +# +# A port for passing framing / deframing data +# This is used by the Communications components which need context to interpret framed data +##### + +module Svc { + + @ Port for sending communications data (frames) buffer along with context information + port ComDataWithContext(ref data: Fw.Buffer, context: ComCfg.FrameContext) + +} diff --git a/Svc/Ports/VersionPorts/CMakeLists.txt b/Svc/Ports/VersionPorts/CMakeLists.txt index 2d33657ab3..ffbace1241 100644 --- a/Svc/Ports/VersionPorts/CMakeLists.txt +++ b/Svc/Ports/VersionPorts/CMakeLists.txt @@ -6,4 +6,4 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/VersionPorts.fpp" ) -register_fprime_module() \ No newline at end of file +register_fprime_module() diff --git a/cmake/test/src/test_unittests.py b/cmake/test/src/test_unittests.py index 036c7dfe4a..3fe37b4db8 100644 --- a/cmake/test/src/test_unittests.py +++ b/cmake/test/src/test_unittests.py @@ -48,7 +48,7 @@ UNIT_TESTS = [ "Svc_FileDownlink_ut_exe", "Svc_FileManager_ut_exe", "Svc_FileUplink_ut_exe", - "Svc_Framer_ut_exe", + "Svc_FprimeFramer_ut_exe", "Svc_GenericHub_ut_exe", "Svc_Health_ut_exe", "Svc_PosixTime_ut_exe", diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index e66e17c036..a506e89530 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -8,8 +8,9 @@ register_fprime_module( AUTOCODER_INPUTS "${CMAKE_CURRENT_LIST_DIR}/AcConstants.fpp" "${CMAKE_CURRENT_LIST_DIR}/DpCfg.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ComCfg.fpp" "${CMAKE_CURRENT_LIST_DIR}/FpConfig.fpp" + "${CMAKE_CURRENT_LIST_DIR}/FpySequencerCfg.fpp" "${CMAKE_CURRENT_LIST_DIR}/PolyDbCfg.fpp" "${CMAKE_CURRENT_LIST_DIR}/VersionCfg.fpp" - "${CMAKE_CURRENT_LIST_DIR}/FpySequencerCfg.fpp" ) diff --git a/config/ComCfg.fpp b/config/ComCfg.fpp new file mode 100644 index 0000000000..4dfd70a800 --- /dev/null +++ b/config/ComCfg.fpp @@ -0,0 +1,18 @@ +# ====================================================================== +# FPP file for configuration of the communications stack +# +# The only reason to modify these definitions is if you are writing your own +# Framer/Deframer implementations and need more contextual data than what is +# defined +# ====================================================================== + +module ComCfg { + + @ Type used to pass context info between components during framing/deframing + struct FrameContext { + comQueueIndex: FwIndexType @< Queue Index used by the ComQueue, other components shall not modify + } default { + comQueueIndex = 0 + } + +} diff --git a/docs/reference/communication-adapter-interface.md b/docs/reference/communication-adapter-interface.md index bb0bb1164c..e28d040ea5 100644 --- a/docs/reference/communication-adapter-interface.md +++ b/docs/reference/communication-adapter-interface.md @@ -1,7 +1,7 @@ # Communication Adapter Interface Any communication component (e.g. a radio component) that is intended for use with the standard F´ uplink and downlink -stack should implement the *Communication Adapter Interface*. This interface specifies both the ports and protocols used +stack should implement the *Communication Adapter Interface* [`ComInterface.fppi`](../../Svc/Interfaces/ComInterface.fppi). This interface specifies both the ports and protocols used to operate with the standard F´ uplink and downlink components. Implementors of this interface are referred to as *Communication Adapters*. @@ -19,18 +19,20 @@ stream driver model for backwards compatibility. | Kind | Suggested Name | Port Type | Usage | |----------|----------------|-----------------------|----------------------------------------------------------------| -| `input` | `comDataIn` | `Drv.ByteStreamSend` | Port receiving `Fw::Buffer` objects for outgoing transmission. | -| `output` | `comDataOut` | `Drv.ByteStreamRecv` | Port producing incoming `Fw::Buffer` objects. | -| `output` | `comStatus` | `Fw.SuccessCondition` | Port indicating status of outgoing transmission. See protocol. | +| `input` | `comDataIn` | `Svc.ComDataWithContext` | Port receiving `Fw::Buffer` objects for outgoing transmission (to be sent on the wire) | +| `output` | `comDataOut` | `Fw.BufferSend` | Port producing incoming `Fw::Buffer` objects (received on the wire) | +| `output` | `dataReturnOut` | `Svc.ComDataWithContext` | Port returning ownership of the `Fw::Buffer` sent on the `comDataIn` port | +| `output` | `comStatusOut` | `Fw.SuccessCondition` | Port indicating status of outgoing transmission. See protocol. | > [!NOTE] -> components implementing the *Communication Adapter Interface* must deallocate any `Fw::Buffer` received on the `comDataIn` port or must delegate the deallocation to another component (e.g. a driver). +> About buffer management: after receiving a buffer on the `comDataIn` port, the communication component must return ownership of said buffer through the `dataReturnOut` port. The common scenario is to connect `comDataIn` and `dataReturnOut` to the same component, so that the sender can handle deallocation. +> This is done with a callback so that `comDataIn` can be an asynchronous port if needed. ### comDataIn Description This port receives data from an F´ application in the form of an argument of `Fw::Buffer` type. This data is intended to -be sent out the communications interface managed by this component. From the perspective of the application this is +be sent out the communications interface managed by this component (often referred to as _the wire_). From the perspective of the application this is the outgoing data port. ### comDataOut Description @@ -38,7 +40,11 @@ the outgoing data port. This port receives data from the communication interface managed by this component and provides it to the F´ application in the form of an argument of `Fw::Buffer` type. From the perspective of the application this is the incoming data port. -### comStatus Description +### dataReturnOut Description + +This port is used to receive a callback returning ownership of the `Fw::Buffer` object that was sent on the `comDataIn` port. Ownership is typically returned to the sender. A callback is used so that `comDataIn` may be an asynchronous port if needed. + +### comStatusOut Description This port carries a status of `Fw::Success::SUCCESS` or `Fw::Success::FAILURE` typically in response to a call to the `comDataIn` port described above. diff --git a/docs/user-manual/framework/ground-interface.md b/docs/user-manual/framework/ground-interface.md index 30498088fb..ebda43cbe8 100644 --- a/docs/user-manual/framework/ground-interface.md +++ b/docs/user-manual/framework/ground-interface.md @@ -54,9 +54,9 @@ The driver is responsible for reading the data from the hardware in either conte To send data to a driver, an `Fw::Buffer` is passed to the driver's send input port and the data wrapped by the buffer will be pushed out to the hardware. Drivers respond to sends with one of the following statuses: -1. SendStatus.SEND_OK: indicates the send was successful +1. SendStatus.OP_OK: indicates the send was successful 2. SendStatus.SEND_RETRY: indicates subsequent retransmission will likely succeed -3. SendStatus.SEND_ERROR: send failed, the data was not sent, and future success cannot be predicted +3. SendStatus.OTHER_ERROR: send failed, the data was not sent, and future success cannot be predicted **Polling Data** @@ -77,8 +77,8 @@ has an internal task that calls the receive output port when data has been recei nothing to retry. -1. RecvStatus.RECV_OK: receive works as expected and the buffer has valid data -2. RecvStatus.RECV_ERROR: receive failed and the buffer does not have valid data +1. RecvStatus.OP_OK: receive works as expected and the buffer has valid data +2. RecvStatus.OTHER_ERROR: receive failed and the buffer does not have valid data ### Uplink