From d0246f148b879907df4e9ae5d5239e75e5b8d359 Mon Sep 17 00:00:00 2001 From: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com> Date: Tue, 29 Apr 2025 16:40:36 -0700 Subject: [PATCH] Add Framer FPP interface, implement FprimeFramer and adapt ComQueue (#3486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial FprimeFramer and FprimePacketizer * Code clarity + set up UTs * Rework ComQueue and ComStub to use DataWithContext * Add packets to RefPackets.fppi * Fix ComQueue tests * Add hotfix to FileDownlink instead of ComQueue * Fix cancelPacket as well * Fix ComQueue UTs by removing hotfix * Refactor DataWithContext to use an FPP object for context instead of Fw.Buffer * Touch up testing * Add docs * more docs * More docs * Rework buffer deallocation pattern to pass-through ComQueue * Update ComStub UTs * Restore original FileDownlink.cpp * Formatting tweak * Update deprecated getSerializeRepr() calls * deserialization methods * Fix spelling * add cast for safety * CMakefile change * Bump ComQueue depth * Update RPI deployment with new Downlink stack * Rename comQueueIn port to comPktQueueIn * Fix comQueueIn to comPktQueueIn change * Remove legacy Svc.Framer * Fix CMake UTs * Fix RPI topology config * Fix FprimeProtocol.fpp module * Fix namespacing * Use const reference for FrameContext port * Review comments EXCEPT port passback refactor * Rework ComStub with new ByteStream * New ByteStream - ComInterface model * Rework TcpClient / TcpServer with new bytestream * Adapt UDP component for new ByteStream * Adapt FrameAccumulator for new ByteStream * Adapt FprimeFramer for new ByteStream * Update Ref topology with new ByteStream model * Remove all legacy deallocates from Drivers; reintroduce DEPRECATED model types * Fix spelling and include error * More spelling.... * RPI and RpiDemo fixes * Fix conversion warning on RPI * static_cast for short int on RPI * Standardize port names * Remove legacy Drv types and merge RECV/SEND enum type, delete StreamCrossover * Update SDDs * Update SDDs * Fix ComInterface <-> Framer interfaction, clarify comments and fix annotations * Switch ComStub from ASSERT to log failure and return buffer * Add history size check + clarify test handler overrides * Fix RPI topology to wire comStub on Uplink * Rename comm to comDriver in RPI topology * Update communication adapter interface docs --- .github/actions/spelling/expect.txt | 3 +- .github/actions/spelling/patterns.txt | 9 + .../ByteStreamDriverModel.fpp | 42 +-- Drv/ByteStreamDriverModel/changed-symbols.txt | 26 -- Drv/ByteStreamDriverModel/docs/sdd.md | 54 +-- Drv/CMakeLists.txt | 1 - Drv/Interfaces/ByteStreamDriverInterface.fppi | 11 +- Drv/LinuxUartDriver/LinuxUartDriver.cpp | 27 +- Drv/LinuxUartDriver/LinuxUartDriver.fpp | 3 - Drv/LinuxUartDriver/LinuxUartDriver.hpp | 2 +- Drv/StreamCrossover/CMakeLists.txt | 22 -- Drv/StreamCrossover/StreamCrossover.cpp | 57 ---- Drv/StreamCrossover/StreamCrossover.fpp | 28 -- Drv/StreamCrossover/StreamCrossover.hpp | 53 --- Drv/StreamCrossover/docs/sdd.md | 29 -- .../test/ut/StreamCrossoverTestMain.cpp | 20 -- .../test/ut/StreamCrossoverTester.cpp | 101 ------ .../test/ut/StreamCrossoverTester.hpp | 99 ------ Drv/TcpClient/TcpClient.fpp | 5 +- Drv/TcpClient/TcpClientComponentImpl.cpp | 31 +- Drv/TcpClient/TcpClientComponentImpl.hpp | 13 +- Drv/TcpClient/docs/sdd.md | 28 +- Drv/TcpClient/test/ut/TcpClientTester.cpp | 28 +- Drv/TcpClient/test/ut/TcpClientTester.hpp | 21 +- Drv/TcpServer/TcpServer.fpp | 5 +- Drv/TcpServer/TcpServerComponentImpl.cpp | 31 +- Drv/TcpServer/TcpServerComponentImpl.hpp | 5 +- Drv/TcpServer/docs/sdd.md | 27 +- Drv/TcpServer/test/ut/TcpServerTester.cpp | 22 +- Drv/TcpServer/test/ut/TcpServerTester.hpp | 21 +- Drv/Udp/Udp.fpp | 2 - Drv/Udp/UdpComponentImpl.cpp | 33 +- Drv/Udp/UdpComponentImpl.hpp | 5 +- Drv/Udp/docs/sdd.md | 25 +- Drv/Udp/test/ut/UdpTester.cpp | 23 +- Drv/Udp/test/ut/UdpTester.hpp | 21 +- Fw/Buffer/Buffer.fpp | 4 - RPI/RpiDemo/RpiDemo.fpp | 7 +- RPI/RpiDemo/RpiDemoComponentImpl.cpp | 20 +- RPI/RpiDemo/RpiDemoComponentImpl.hpp | 9 +- RPI/Top/RPITopologyDefs.hpp | 1 - RPI/Top/instances.fpp | 54 +-- RPI/Top/topology.fpp | 39 ++- Ref/Top/CMakeLists.txt | 4 - Ref/Top/RefPackets.fppi | 2 + Ref/Top/RefTopology.cpp | 28 +- Ref/Top/RefTopologyDefs.hpp | 1 - Ref/Top/instances.fpp | 40 ++- Ref/Top/topology.fpp | 57 ++-- Svc/CMakeLists.txt | 5 +- Svc/ComQueue/ComQueue.cpp | 63 +++- Svc/ComQueue/ComQueue.fpp | 21 +- Svc/ComQueue/ComQueue.hpp | 38 ++- Svc/ComQueue/docs/img/ComQueue.png | Bin 120421 -> 33811 bytes Svc/ComQueue/docs/sdd.md | 55 ++- Svc/ComQueue/test/ut/ComQueueTestMain.cpp | 10 + Svc/ComQueue/test/ut/ComQueueTester.cpp | 171 ++++++---- Svc/ComQueue/test/ut/ComQueueTester.hpp | 23 +- Svc/ComStub/CMakeLists.txt | 4 + Svc/ComStub/ComStub.cpp | 55 ++- Svc/ComStub/ComStub.fpp | 14 +- Svc/ComStub/ComStub.hpp | 25 +- Svc/ComStub/docs/sdd.md | 8 +- Svc/ComStub/test/ut/ComStubTestMain.cpp | 5 + Svc/ComStub/test/ut/ComStubTester.cpp | 158 +++++---- Svc/ComStub/test/ut/ComStubTester.hpp | 25 +- Svc/FprimeDeframer/FprimeDeframer.cpp | 2 +- Svc/FprimeDeframer/FprimeDeframer.hpp | 2 +- Svc/FprimeDeframer/docs/sdd.md | 8 +- .../test/ut/FprimeDeframerTester.cpp | 2 +- Svc/FprimeFramer/CMakeLists.txt | 32 ++ Svc/FprimeFramer/FprimeFramer.cpp | 75 +++++ Svc/FprimeFramer/FprimeFramer.fpp | 24 ++ Svc/FprimeFramer/FprimeFramer.hpp | 66 ++++ Svc/FprimeFramer/docs/img/framer-topology.png | Bin 0 -> 37179 bytes Svc/FprimeFramer/docs/sdd.md | 42 +++ .../test/ut/FprimeFramerTestMain.cpp | 27 ++ .../test/ut/FprimeFramerTester.cpp | 93 ++++++ .../test/ut/FprimeFramerTester.hpp | 83 +++++ Svc/FprimeProtocol/FprimeProtocol.fpp | 8 +- Svc/FprimeRouter/FprimeRouter.cpp | 4 +- Svc/FprimeRouter/FprimeRouter.fpp | 2 +- Svc/FprimeRouter/FprimeRouter.hpp | 2 +- Svc/FprimeRouter/docs/sdd.md | 6 +- .../test/ut/FprimeRouterTester.cpp | 5 +- Svc/FrameAccumulator/FrameAccumulator.cpp | 10 +- Svc/FrameAccumulator/FrameAccumulator.hpp | 3 +- Svc/FrameAccumulator/docs/sdd.md | 4 +- .../test/ut/FrameAccumulatorTester.cpp | 16 +- .../detectors/FprimeFrameDetectorTestMain.cpp | 2 +- Svc/Framer/CMakeLists.txt | 26 -- Svc/Framer/Framer.cpp | 87 ----- Svc/Framer/Framer.fpp | 50 --- Svc/Framer/Framer.hpp | 113 ------- Svc/Framer/docs/img/.fpv-env | 1 - Svc/Framer/docs/img/Framer.png | Bin 109683 -> 0 bytes Svc/Framer/docs/img/top/event.json | 48 --- Svc/Framer/docs/img/top/event.png | Bin 33543 -> 0 bytes Svc/Framer/docs/img/top/event.txt | 6 - Svc/Framer/docs/img/top/framed.json | 109 ------ Svc/Framer/docs/img/top/framed.png | Bin 81211 -> 0 bytes Svc/Framer/docs/img/top/framed.txt | 20 -- Svc/Framer/docs/img/top/framer-file.json | 76 ----- Svc/Framer/docs/img/top/framer-file.png | Bin 65865 -> 0 bytes Svc/Framer/docs/img/top/framer-file.txt | 13 - Svc/Framer/docs/img/top/hub.json | 63 ---- Svc/Framer/docs/img/top/hub.png | Bin 37919 -> 0 bytes Svc/Framer/docs/img/top/hub.txt | 13 - Svc/Framer/docs/img/top/tlm.json | 48 --- Svc/Framer/docs/img/top/tlm.png | Bin 31864 -> 0 bytes Svc/Framer/docs/img/top/tlm.txt | 6 - Svc/Framer/docs/sdd.md | 313 ------------------ Svc/Framer/test/ut/FramerTestMain.cpp | 75 ----- Svc/Framer/test/ut/FramerTester.cpp | 196 ----------- Svc/Framer/test/ut/FramerTester.hpp | 157 --------- Svc/Interfaces/ComInterface.fppi | 23 +- Svc/Interfaces/DeframerInterface.fppi | 4 +- Svc/Interfaces/FrameAccumulatorInterface.fppi | 6 +- Svc/Interfaces/FramerInterface.fppi | 28 ++ Svc/Interfaces/RouterInterface.fppi | 2 +- Svc/Interfaces/docs/sdd.md | 27 ++ Svc/Ports/CMakeLists.txt | 4 + Svc/Ports/CommsPorts/CMakeLists.txt | 9 + Svc/Ports/CommsPorts/CommsPorts.fpp | 13 + Svc/Ports/VersionPorts/CMakeLists.txt | 2 +- cmake/test/src/test_unittests.py | 2 +- config/CMakeLists.txt | 3 +- config/ComCfg.fpp | 18 + .../communication-adapter-interface.md | 20 +- .../user-manual/framework/ground-interface.md | 8 +- 130 files changed, 1367 insertions(+), 2619 deletions(-) delete mode 100644 Drv/ByteStreamDriverModel/changed-symbols.txt delete mode 100644 Drv/StreamCrossover/CMakeLists.txt delete mode 100644 Drv/StreamCrossover/StreamCrossover.cpp delete mode 100644 Drv/StreamCrossover/StreamCrossover.fpp delete mode 100644 Drv/StreamCrossover/StreamCrossover.hpp delete mode 100644 Drv/StreamCrossover/docs/sdd.md delete mode 100644 Drv/StreamCrossover/test/ut/StreamCrossoverTestMain.cpp delete mode 100644 Drv/StreamCrossover/test/ut/StreamCrossoverTester.cpp delete mode 100644 Drv/StreamCrossover/test/ut/StreamCrossoverTester.hpp create mode 100644 Svc/FprimeFramer/CMakeLists.txt create mode 100644 Svc/FprimeFramer/FprimeFramer.cpp create mode 100644 Svc/FprimeFramer/FprimeFramer.fpp create mode 100644 Svc/FprimeFramer/FprimeFramer.hpp create mode 100644 Svc/FprimeFramer/docs/img/framer-topology.png create mode 100644 Svc/FprimeFramer/docs/sdd.md create mode 100644 Svc/FprimeFramer/test/ut/FprimeFramerTestMain.cpp create mode 100644 Svc/FprimeFramer/test/ut/FprimeFramerTester.cpp create mode 100644 Svc/FprimeFramer/test/ut/FprimeFramerTester.hpp delete mode 100644 Svc/Framer/CMakeLists.txt delete mode 100644 Svc/Framer/Framer.cpp delete mode 100644 Svc/Framer/Framer.fpp delete mode 100644 Svc/Framer/Framer.hpp delete mode 100644 Svc/Framer/docs/img/.fpv-env delete mode 100644 Svc/Framer/docs/img/Framer.png delete mode 100644 Svc/Framer/docs/img/top/event.json delete mode 100644 Svc/Framer/docs/img/top/event.png delete mode 100644 Svc/Framer/docs/img/top/event.txt delete mode 100644 Svc/Framer/docs/img/top/framed.json delete mode 100644 Svc/Framer/docs/img/top/framed.png delete mode 100644 Svc/Framer/docs/img/top/framed.txt delete mode 100644 Svc/Framer/docs/img/top/framer-file.json delete mode 100644 Svc/Framer/docs/img/top/framer-file.png delete mode 100644 Svc/Framer/docs/img/top/framer-file.txt delete mode 100644 Svc/Framer/docs/img/top/hub.json delete mode 100644 Svc/Framer/docs/img/top/hub.png delete mode 100644 Svc/Framer/docs/img/top/hub.txt delete mode 100644 Svc/Framer/docs/img/top/tlm.json delete mode 100644 Svc/Framer/docs/img/top/tlm.png delete mode 100644 Svc/Framer/docs/img/top/tlm.txt delete mode 100644 Svc/Framer/docs/sdd.md delete mode 100644 Svc/Framer/test/ut/FramerTestMain.cpp delete mode 100644 Svc/Framer/test/ut/FramerTester.cpp delete mode 100644 Svc/Framer/test/ut/FramerTester.hpp create mode 100644 Svc/Interfaces/FramerInterface.fppi create mode 100644 Svc/Interfaces/docs/sdd.md create mode 100644 Svc/Ports/CMakeLists.txt create mode 100644 Svc/Ports/CommsPorts/CMakeLists.txt create mode 100644 Svc/Ports/CommsPorts/CommsPorts.fpp create mode 100644 config/ComCfg.fpp 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 /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

PkKys3CAZ@ibR}Vh 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 qqi9YV [!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 0000000000000000000000000000000000000000..c67c69029beb2d21c5cb11c31f650b82e7a895cc GIT binary patch literal 37179 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 JWuis_{|};T`Jey* literal 0 HcmV?d00001 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 bf86d6b49328b57626f055678748541905aee425..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109683 zcmeEuc|4SR`+rF_(I#6Z5yeTCiU?U+qzK8rhmd7V_MKEJdnHTuWXrzqh7`&kAqHdL z$5_TTw%>L4ea?BF=RD6-=l|dNqu0xs!^}OO`}4W3_jcXhx8ViA z*|u#DY1=jm5^5K`BDrxAUf9lQdiCmU^Q+QVF%}qWr3dgS>#Hzr?f%0D`#)}@ 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≪-;v`onT^@W$MdyPIkeCOa@WunEWieYE} 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 ZQ;OqJF3eOJJ=`+*8Sg!?2QtHh{|iVsPwM~x 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 f5852898789bedd74cd7495f0bb1c675074058ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33543 zcmeFZby!?Yvp9&8Ab|u89v~3h-8}?%3-0dj4nY%wy9IZ53lQ7~86;S6*8l^1CVB7u zzWsf7|KHu`&NDNo=k)2S?y|0`E{If=mqJG&K!JgQL6?3nt_%Z%NCmW4pCJL?WM!)< zFfeE~mSSRx(qdv{ica=smNup^Fz+K1HIOw`hH$fVzQo5*!o7@t<%K2g_4$=(6d9RX z^~*29qLFXj6fcbA1zF=MmG72D(0Sf*;p@E9 zWj_8;w4CaF0+X{ilK8$>i2=sxyXW*mHQBG*Eo`bi8ZtOJVc5#<#E}GPO%|5VFvA8< z?w@`DbtH=op8ZsA^Iz?hJKxAb|ZHMRYr|8*nk1wV)I`YtYmQm<`J3wKA-Vn#$ICH zUxa)V{QhY{YHLeY?Wb~tZEgpG5kAK0hx=HzP5TE+v4@X#1DNW+ILNGe$WtlP`8J>E z$DWchY<}lpST7WdT6&a|`)l@rwNxmuQ&1d}xfy7+m8>JYC45X*V1;Q!Jw1Y^NjNr! z7OMRMU~Aa235j59UVhKrI4pjjD9E6TJsgN%iR;q(E)EN$M)11~LTx;E;uz=NtY#up zJ+JPtS;-|{^E7N1iay4+)^mECC&Ju-{Eb0&l#nxNOck=mQM|X3BIU3(3G{S~qNZ%E z!argO>OT(~8C&ih<)F}6EL%ifPm*3E*xmIxDHHkZ! zUkWOS9<%Nhk|#p#+2`PvQ^cM(!^<^0aE_uGpNcfT;9-|#M5$0Nve0@je~c&oHkmGV zNHr3tGS-iE@pD7@-N8syi3d7!Fk;BHLkD(Ia;{^B=Kd~05=@E7$kZ8&>{DLf5iJw=5y} zvS`#{uZ|qVmPv2=Db_hKIq{ZJZ%9Tr(*@RPazjs39D*k$o7p7lh3~|^8jBEaVW`cK zAKh#J1jWw~WAsAE_)G>~H@|WCzLG?$%34AF0N+ijs7ybD?w5h55E-mVsB6(PmB22ebDQ zuY38aQ2mGzWMfly*n{>q4maQeHgxiRd^=3he8eyZ3hi4%9pdgI@9*yqy7tHgVI97s z**!Jd^QNocrUjhrp_X|#S#~Oi(=j64CQXL$jlrbApcW6@r+nD zN2%tZzB7c3@SP3kQ`1{X9}K;i?4GLixKq0axvP%5BuKwNk>v{!z0e z)(PgevFOp>u`M(3SlZ~_sO>1$C|(LFv%i5z&1voXCQa)piz!=6D;|(jl4;?#E?sS6 za^j>_$DC&w28a_R4T`F;F3$$iZ0$ZK6Abkmrkw^=CdhEsFHIrUYkZIz0NewEyo|6(OokSv=8o<#(Ly_HufJi z@~!xm-y7XX-Y}75ktoN}#>p$lOsG!CWi_?CbQrZKdFq~0c_4dETvgsY?ryFp>^T3} zVbYgcqhIUjoR9)X<3_LYw607n#~n1SRE=ftW$$;5buo0)2M{WfoN`Z+$CEbGoxUE4 zO&nSp^upO9qD1ELU6|lrxMUjRRxsSq0kB3ulb<*C0&! zXK~N;ar~l;N7o%`xmS$&2S-Vqse%Yz;?=NhI2QO8u-Dqr^SX^La2TIRX-P!pTjhzc zQ+vr>2IHrvET^muyd3P0rX##zcT+tqU$}6*Y^HJa-dr6-?yrjIN;XI*Q?QVomCZ=e z{CxX{hTGCr8GQSB(>$&#!zP9PL#5oCLdtK4ANEo)Sq)c0Vk3{SP^nilOxP^%3ZfFw zsm&Dx1tpwO+=tgyMXi+gS7#@dE$n!jsACcuX)4kOe^u;sY$2b|pYtL51VO z&19S3nwAgkVk1413DG5Qw8-CeHS_od8pY6>(rT-_t4pZG*ec#G_(gui7c+>H&y?obEC07{}U!}WG|MTHU3FArZcy^b} zVeYwA?!vRxy|bdK?APw!_H4c{qV9-JWC~93`kx1_h2BL8;>GEnx2ifXZaQ7z+|Wt+ zyFWoJ5~NhF)F#Rr##YB%8S-`H>yhfST5)}jmR-lMM!53q>X&7kJ?}x^b!?k{H)XF4 zbza=rJ+5?mUmRl{;|WZ9DV|U68vZ7A^Cz;nu;6=qcRQ6h=ooj>aIvH>_*vlha?LKy zk>wEEj5*GPZq~eem>XwT%4yza;g+es#(MUWznz!q{r(UAK!4pmlC_mH?Yq{evDzji zd-pD9@A(C+nTu23@%v5;i4LR=Z$U3#{wJEfnYvEPZ0T&7t_9zcdxEnoKYw}ut`NHI z7Y`@~)wz3nFzt)zFbuC@c=?-@sNPKk!3VvYsDgj?KwZwy^dbToMy*=qVW5r>hWlCi z75@+P^bI^gLCl=WN-?>&wJsWXZ}D)lLY{R%Aoek^WOJ~m5=(1qO)XtdBl7r%#4rR- ziROx-nCq#AI@NG1T5Ogiw<2G6W=@9>BFtT3kfc1NLym-GOK)b>|E(G6JFJ*%yOx9=dpJnoq+$ z((>N&*4{_ptD~d|_w9<-va+_;`lscU)k@z3-JR-28yRb!cUqsxC8P^doMEt1oZ+5h zzP@=Nsiuklt_Xu{W5m2x`3h!SR>9rhOZDQqD*MKl?GBv)M5Ku+3!2QS9PdJ1GAI$$82ZcrE1{*ZAFtkYapTnS_FlEnQ|34sIKm>47n+N{~ zx<6A8W*##CA14coV1!4O5}lcWPX0g5H2|iEGW&m8BycZ6H^6|^&51MOe^?^`3s@x5 z|1R?X@0<)|#FI5MF$swtEssx~yX!indm8^Sisprm`d5N=C2|(s3R+5N*f}`w{KsO@ zH6E`A(+D8HD{H$Bk)h9YBctxNQm`FB4&svz5^kQxIEIi3&rzU?73hJOmY!bK`J%-~ zciQJSZ(&Kx5aUOet7+FHMl4xL{maFcmN!+^@3yWEan8MQ!6zH>`pa}%I1LZSpY<_o zYwOx#$-IN0;u(JpHzqfh+u2C?3xaDSsX2%T&A+{CYv$g;r&Rz^hiTQrGks=MqFVLj#Lbk z3X>d&dDgFVt?N5UA|G{Kk7c=Q+%>oxt-Xu+9S?`C?RKV?K?baCQgMo`)%0lDj#9ge z_5p}rLf_C8N&TqL`GWYz5(FNT=SYeeiv?@Qsb})w#2zjX$g3VU@}(xOY-94gfKI9q z@zdQkswvjDFh2^((4dV~k&fow!o=yKubEO%Gh`tq+$TFX5Au@O-V4TAp9IC^o^PFT z>b+hQYhp-Iy*Zp_*{t~Bl(rIch=;ArDlg+hoyG75YM_=$0tfEy6m>lrGZvcoh*oOe zX7IUfT^~Nvk$?g|J&1dx7z}xnP!zrz9Of~>fX>qYM*sqZ-EkF#wcJa1GlcxuiI!^x zGnShMQE2we1g%|&0)pHnN(fM5KeY_Xy_KzIa zw<0HJXBR*tc8kU}$O#=tXlN8Wqv*kd3NKs|noV~Sxg?>Z-opl(r9VFjQj@XMzt-k% z@XtmUT;VVqkb&iOdkO9TK-QGQj7G%8BCCB_t(#yn6HG@Vr~Y@WD{M@7*TIVE`swu; zXVlGaO$=&4bm;h~qdT4T@Oe$mCh-&K|H^YgTR^K!2Cw2v&W`g8g;=bytmI=xA|XH? z9m)_`S?kJoK$Fa8tH@%~dp~s=Ua#T-xB=b&`f8Grd;5g(N~?_n$@HU4d5=jX`a1!` zo{dTSg&)naaYui5*U4?feQT@Uu;eF9dC~y(U)ac-HakO~+JvKY^^g=54@OuK>r^4Sna7;29CrG65WXJGro6 zpxZ*%n>4TgESYxmi1)MlBoRH(YXAo?8BLvrPR8=zkQqTjz5KD*!9TJ( z`5TVM)6;OFe$g;P&Z{qkEAwQ8@6YyJ&=@d~R<7AKOx5d2J*!(9yKP|foQjQ=wO2U( z$gbUWlW~8AD+%71;vdSVb;oYoFVL@~i;jg3tAbsxp|pMfJWvlFIs9|oF^U+KoJ=Id zl=`puMd!bm8wYF*8%-I(~yy6uR8otN9{2=I=t|t>C2GkDj%u z)1xMWLWBO;g`5jSB!v{4o~@PDsIrT-O!vQ{Np^)eo9X=&Hn-mW&9#O|mL7nquHL+9 zoc$b7n6Sf)jQ<;0yorn#>3Y7a$MVMt4Z7z3z{~=_V&Zd{+u`$gSH^g*vAw-c&in_o zUEoq_se{2qYxTv^+Zr3*MgynyY(ECfP1hmiU#>f%0-IHsm=2d$k2n!HmLcWi!(3H(JGt3r>}EkN z`XA|>#nFVc>4$E553Ah3EI0%Aa!^qLJyBGgqx@&q;@;N66Y}fZ zz@(zSx&MODk|t|it*E+uT>R(HQv-GUAy9!n6#Ul{Pz!XJ7ZvpZZ&EhvO*yww1t-(vK%D3binn*Vk8GOYhYANS+{$Yj5Oqhppb<7n-J6@h0rK- zh0s!Gb1`{4yVN8Lf(FqGD{!?f&q7 zq0Y^eyVg01!%03QthF^hH5KRF3pYH_cpzNFm@3Rr#mq~rsEm~G9ty@q0^9cRDT?cu!y+- zws9tc+D~)9vbuevI&qzW8>VzEYG`Sp+4_a|@k$UU9TZkEqW7Gd?%KoHeD<)dFJn;1 zanAboPf#N~2!!K&b^`=Z7~Y7}Z&Fm>EdtJ8(!(WRZqL%W%CR>)S|&dQ(OMl_x!+@| zqVJ=P=0jl@itljP)JRDODbXKF6r=+CL|W!)rB`#Z4SiaNI`QJdB<8o3rvh*@5zV)MY(JI*B-tUMQAp)MoYq$9BY*z_7CXj?DPbZyWxu z^27ghcZsUPkV3?6r))9pkuZnXF{q++(y7NY)O>mb**fI~I7ilj@QiBaz{hEBP+f#gYzdbTJGCl?}niYn`^KB%dhEi8PIRa;zDK(B&sbJGeyf}ww+ zrB!f#el}!jzcfBGozQCwC#3w)Mu?UJfnD8LZmz#9mX(dIuT^;~ETf&@p5EecAjxi) zp-z8i;g*T#TCjq;4diV}xL=w(WahPS=#^@VW>7J|*Rjv2hP*;Nmv__Uvfe(HlZoYo z>K#T;Xe}Al2%1$Sy{`0T`r37)-t4e%g3sbBp8~lZgm@kqSNjTBWBn}m|9ztoG(;0c z^1}Ey<)o@5m2_#4moG^hEQLP2($^X*Wfr-rkZ?8&uCe|m@)~;qEm!~r#bRU^Kyut#2g+wTWG>S{ z)Uxxh#yCaHIvPSb{0f&kXg!MCT!#GS!ymFb7&WXK%W-szX2Fe+wC{RrcV0V7H|p~) zM{%)YY|+$d4l4Jh2f=7<15<(r5Lbwr=JX)=ETp!=^f%N2Y1RucIQL5U>LIS*y`wqJ12zlKH@#yzMC1qg#Y-hbmu>W3hO1m+L?)?`8%zZAS9 zQ_U7K*MDfqb@?hsZ|u&?aqpTCYB_k51U_6q?tSa6r{9j!fgOZiy+6MwaF zvo!KeFArNDdF6s;UIXFUv(ip}SBLEI&=^qvcWp_MpNVKhM0e=Ko^NGsA#aLnHw8`W z(6V@(e)P^Jk!i-{^P_5Uyi~9=RQgc^8EdF+Jc(b|P_N*3B?qEbx{ut>!-RIL1~o?| zpTAaJoui5+apa*?^vqdz3u9QNr>Bj17kO)dZNfggE1d}b5@_rPuZp2(MO}CDy0dCf z$fEbar_YDgNnxb=tK+j8mS#(#^NvF!hx)g|%!^4VaZo2SlVUP6cnGkx;4MyY#h4d! zM)3miI58j5dDJH{q4ce9#R~fNq&EzN$F|!SgK>8kDErv#v>vlwDC8U@rhCOTA|l(7 z9c{f@-lPJR2ly+?^U9olpPB+)XLJos@^#}r))SsRcDiN8Ys}76`i6ySTOS;xiHeDH z=vb5Gs&~)_Y=|O>PqvK#VRu1-IErywk544IZQ~b0cCgmQV4RfRN}} zbqpsA_72SJSBsR6Kv3P=W7fDmmbWG?blGB$R}FQ`HJaEl4=eK;E9MVmT1SJJI^qU= zRq-4BFL>9eLrpzF%u31DW0USfy-FN<`=w=KRnsDd%PTia{-_-?gX4+zp}{&JZ_VOQ z;=Z|MFZ22Gv3{-Ld1*(KN=nuCm?R?BS@9FsJJRA*TM4cLyfH6dyH@WM{I=~ z{qJAAqZ6U4GKR)}jx`;A)m%;=q++im6G()t^!8umPpYD`s%5KZ@!K7!hxLHoB{a3x zW%INP5iK{e5Y=5!WZPV%weBjV_xpqrPZ-`4u`m7HjJx&7tRU2xay)}7Z9Fsq3=f#{ zpP=V1I|j;JKj&}-j74%PWoAM1V|RkV;q|IKrAt#@C?yPK@d`&O4QDvAw6`j8@6_;P zJDf#QT5pxS$C9cKI=1~-kzz7UxQ=DoV>MN9aXkn(PkA(KKJkzzUDA4^wD zohWE`FJ7T?Ahyd&@4^1-ajy1ao9 zS}a$0wp0VK{Z zE84GZeU4hH&9B;49h7gu_6zS(;|CX4X3z8>x8pNHj`pq^8rx+A>fScWISlrXQ{&RX z$m27l57o#mIE3oqo7Y;CJHk84bH%0Ys>X6Si6})JxYRub*{}QnXNeF{aNC?yOsLZ$ z4Y$IR5*;yXZ9V7Q^#Yl*;;M0Xwm)vMVTkesuA*CceOu2Ok1l7l#<0liiWDEEB0PC% z$CYEwaKVHQErpe$-0wKmVf53pfw2y*QJ>pSg{P}p1`N){cl*s@j+GNH*!;R!h24_=Z2vB!_M zJAJ1mb?p$}>xJBE?>X@5ruAJgDUeW+zalYdJ6tMS{zRinTtYj-Cv;Bj#@|2^eXR48 zg

Osb`Ux_qH(jNIQ2iSP2KGn4$8T=TFAqpU7SJJk{&|)!M^A6bUOW+Dx)p{jQ8Q zY*wq@4Gp2$oGZpcvf+qkH1#2>$J~j(=?WojxzV|NS%LR*XY&ZZiOSEbUkY8DbD#20 zQp{num{0sZb~<@3SQ+lLEBN)4F{$+zOC*M;>-n!9laSP$k=ONMt=&%OnHKXEp_~mf zu+Mq0)R8`g_)pOp%<9fwF+KGJ&A9snrF&-I2HESM6d5>;Olv&I_#Wz__GVBE=7v|% z4SFf(MJD@7uz@R<22Mfi_pZl$`+HrD z(2mVx?Ok;>T!($eGbB|0owS(o3R=U4cM+=wJvBrwTsNP)9xy=F1jp-J*G+mD_nhUm zNE%E}fJZpCB%{Wlt6E;xLSO_i_-YX<|c(lD^3+75j(T~QL``D;0b1h`vCj3_<0 z{#OT&h^{hRF6pZex1B2_vZc!Mx)F14d9>M+h9eAvv5*#n!);>;&wn%Vb18iW#rOH^eOeibyr_(m`kc%cG_fo(MCX2Q=GE`zUhcQr9rCr#ceexYOYdO6-9nOd$MT> z)iO)@O0@~bj?k^&(fG{XvUtg>#Z8?rKSAtQB}|K5F*N!MvSxTD8?)}gPy5DxrGW(( zWN`@~bpPK>{<|xUa{}VV^WsqirmTv|9t=0WXG|S3GHTn4)hh(jyp2X}_Yb%8PYD>K zwoPsj*SoVveGQTgD0zQ=g6Y}9L3xB`>v@6W&uJ>l`rP=Whb_`W$$Psly-7udsTe+l1;}t_ByW%d5+-lE2x(T6LTGdj8t_W-OtErjxbmCgDns%HaYv=S{5S#_ z$Buo4nCEJOde5nzMuVj9zg!zk>oq+Vu4zkb)8T%5(OCK(m5ND&RF7DevEHE8RNcmEim|SuG1Gp6??Q|JF=v>G|mK zXLp`m+Y&`JH?>w{aefzFU|wG1 zKX&6Dh=;*D-^-xq6X`F>Qf!`6B|{#(1sU%Q2*;(5jO2P3y_DKob1MhHJ!#uI0`1xZ zcKj9zRwOsCJEX=^4-!8?%J~|TKs^Pm7G*}Pt;b4uwz@*?CW&cQJ8SnXLN|_Y@9LU^ho{SDJOY(F7(LM<;{QaIWBa4#>_MM6(p|t5O3{5 z@hrFN_M1D6!mh1aCT~+3P8Af?VxE1NAXPfURJpXN#%x zWK-%zqn>0dOI0Lkl`gxw>4*tydPj1CUcTK7LGOpTPZad0D*Xit0mgJ|?^09)JU~=6 zp6e%1Qt3bdK54DzF+erBxbR9=+cB&)!5R%>l}@Rm_I0zuBWJAt6O4=RY<^BR_{dtX znjDGFVb?Mg2@6k~*>ZEZ?$42mi)?^Ft+8GcWG=1SbmvnciH+w^Q+U}XfKfqa%jyQj zpClN(M%y^Rccoscct_A|*W82<@h|^78P3IFi*)g~gUI=-_VAiaPjeWMsGGnlKZ?sH zG8NtSDqR;mWwij5VfN=TtUV@kEi)t=V}A542Fiv7r92AYfO!HNZLE8Xhk=I;JrW-) z#bfJaF)&y7n2g@JBO!sy5oh*A+V3#$2UzO#|+#p?fT4PKRtB zDdDaA`@}p49dpf#rorac>Ow1-bGmA33RVN>6r619%-*DOU-OS|OP%JPB1#qK$WNv} zZ?@C52u<#X$5!Naf(EWfYaIC$UdlGst}6iPx@LewgJYV|B$7oH(7q3nR^u*RDR-RV z$jx5@6WHq-E0DXsThL$v5~3~g6= zM-~rB1cdNP?i@JPZ?R-)EoMxZhty>`7bw|K-rj)e*9oNRdPm(VHGkc6jSl$Ce&;KF zXWLO6^&ojLT;bpvf!OGr{g5$%WWkez9Jvj``N-x$7jU@f9)PissiC?BYZU34Zzs^# zvZ?`_X9mA)TUP+2#%?{hfA_x?gpD0fE@g^3WULM{_AH~j`9k^>ETF%Wux+tHj+k13 zhd4qIrL2~`gdz7$tlz}?&7&kh1Za9wHF_R;?sEhb0@>&@m#~1jIv<1L8Y->&rQMD` zn;Y|#>fF?3`*S53D2pkV7@hA{60eTyou*bTaHvPdQM}G{Z0Kjo;CUUJWPig57C1-k zTT1o=P#}D_hwhnFK)%ZU)v;TJ+x}0%^q2P%2VT{0uyr_cS}`%QIl*njWkw2fQRcR8 z$MCqrG~LshvHM?$7*Jj|>CA80a=wW+>zjcYN8#cib74oV*DD)xRe!w36I^gnNH6gk z=p#LQu5szbpslgK3o5J%TMZ5mnX3D>lt0GMv&AQ)P1R+|F;D=~^7f1#dPQigoG|ir zk(*7Mmb3D?&Z^I1DQ28!{}wUs7fIt53s#CTlM1bpxfM~}Bx)uv?qWi3ov2>rmAz$? zxww7FihUV18mm$K&|(O~q>7l>Ca)w;td+@OJ*~1UheiYt+fn!K@?5lg)dQ)el@8q_ z-9~S4Bl3d5a--1?CfY_8I+=3idZ~0{-cqnnOK9%7dZ?*=`U=yG8S~8*J*GPIlJek^ z6Lt~(d*2&Idg&((S80ug!X!Fl*|d^47E5G@qrR%nyZCwEAl9_Ic?J|VsM!?GU0GW@H0(2l9vS!mEQi1m~XcPSq8AzoO zki`@@RPN7~FNNcf`@r@q)^q;IBGh$8y=l9S^Id)E6Up6$zx_%^RVT%6&(d%cy@$_Y zTR`%XIA6Z`gl($L;4rM(iigP#Co1zu--Ckh5b6A=C(1bcRCMVxJm2-T5WPl!ly&UK z3g11gDv&BOPaje-iQQb3_KTC{4Rlm=&Wd#l8;TH;TtwkWRxpY(92 z&7BqNgdzG<1EsmF$Lv-$O+>?nF;(A%QV}jNeq1Y<*Kn15Ev#3QgWbvLf-#P*<(&z* z9E?I;HlEo4sZDKTc&~cuF;UcYxYBvGyn0pEPOB7HXm+TgxN9t=ZA~*1D`S}7n!4*5 zT0E6U<`Rxr4=<%~im8-a1)A|5rkJ69>wHvW111HsQ#cy<1g!u zfTEIlLeB`S%gTEBI2k)iN#+K!uYY2#mdSYSdlndlars?7*(j%W2{{M;{*e%jVWVqx7#glf;{Q@*V?Q1D@+}zUWQC#!@k*Z0w)T8m|QwY;|fK(^ZTz;p*0;1X~zu956PUY#NvyYrDT8 zB@nNovG07%D_75E@EsqOYDWh%W%Er|t58{4c#u+PI&iRbn@fK;QxzJ>8Dxnelo@~H-2n+6)x7Z0mU%xM}^4hD_#^ZB`g)t{Bb zs~{ET4=kZ=CP138S*^6pf_+F=YZeKOQ5aq2^RBRsXrHM|6ts3*AIiL~+4t(2Z7l;T zoLJcxYDR>?GmVV8+~znHp=MUAxVu(-ytttyQo|KGooe>ueh&$&WGZ5`OL4p0x6tyk z|HwW|qe~QUdL+u>)?J#f)wmr-#;?^ah;|P8I?1oJYp`qC*6DWLDLjFrs8GDFt_dOg zm6@i-^JNufrfUOps}!T)JJ2dayZ+k{dh zRd7=wa!SMJI@XGnkCsRGF(d?~F%{Pk3serA3@astx4N6EI)(vW9Aov?Nr2nraZ;h{ z)~7GVLbI&8XqJ0a_X%a++Pa;gD!1NDCyrfB)2cVi-49}nVd`x2N*4I(=AgT_dwcXM z=5Lh?F;uXG_pO+waz^e%)ozSebfbHveZ8+qS(eN*NsRQ<^a|$(#_3#USNd)3J8;dk zGO%x_w^D zfYw=UV1J=rzZ6F8CW+6s+RoLph+(TJ2-vzD;DJqm@aHKu;Eu-^2)n$TPSrGt$rks(VvHF zT^F=Cq^!y+?@%>8S~VA&Tbx-PC+4|eJa7f_`1IcW17FwXoqP?z42^mQ1fNPY_Q>p; z%B)*x85)W)bGvXjqw9mv8b&xmzV^!N3KyeS7=ED|)wc=U&&VOMY*hy=iE`J#^qrMT zvSvVuu$sUR_Pw1zxdWSLWyu}Y!t+L6iJ$QAzM`Y5lus+qvsQSk?D_t!6JG+#d~Cpl zBSNKZA^W_!foV8qG~%-+oCL@c?&xY`?rIUB{Rr%h61dYm-yXX73&&UB_cfQiu5=*I z%j{Nu>!}sR&{zTu3H@$u)shm(6kZ*u?!*HFbIw6AUpxk7MeSg&v7kumGN`WIeO10wA|dSmViA%IW&Ql zqWe|^=1ImLw-47%fmAdSv2fZt&NzYN({i1A`X);|tIKMo9jR5Tt&+eZq%;ldC1TBn zSgS*y;+I8jbJ`CnN8#gzRP$%4aFEwP`WFT+67UwWz^7JU`6=jg2nyWdo zd5)N+4ZvBR|Jd57tn)DxXDJM~;iv(_3Vd)U8CB^&i*#d+!Z#p3Z^TgbiyD~eKXq0G zKka>y_eZovQfU!!O7~=11oVSY>gy{z+rf3aBRatv)>C+P-t*QI-cnUc3-ikhTZ5Cl ziqTmo(Q6fB*k5Vcua0ql{an{8i?NU$$plIt9mzNrWuMmb+s~#=V^RLjKSc9g4#()55HJac6O7$Zw;2hcH9)b6owrkz)$OJL2qRQN5ERVCD z#2Vr;xY}V{rS7deuensTyF^`S>u#gq$pPii9bgSh{9o_{=}=a0EN1K6d~Fbn%5F8e ztks&V(w#NnF<>jO4mb(~5lbYjv|r6)l!LuIQ@oyx4M#J6=T6dU0nur)YqFeMep}!E zc%GvzR9OO>0U6lDHTMP($O8!WTpD@Qp~=m_bf8YHU5f{Fa1Doo&(T;gQ2LtF^Ba1s zu9>dPd58C>*2-eSh=HCd|FlubO^^ksbKd{*W_@%$*l@C0TJX96>GXQB$(H%J)vCh1 zr_It@Af`vf3=08A)7=&q>H*mSmZ-UZkp%8pK>`qU@@Cq`;s9={@J};n45J=<)!GqY zwgnt67LFnLeQ)z=ioRHw87!JwNG5QW+}uU0PHm8q%|2p-lms~qek#m0>a!v&xQ~v@ zFS%kTiEZt&wvmp>%xB!{vytq1lkn}g?A8iN0#L&n$Vda6+`d&nIiG`n)%=xv0YseFz*g;iIg0E@1zJ2 z-Um>8J8m(acqyE704?`{IDaSkQ*gTM2T%m;|6(B+8*{Q8%%P?R!nw~I`%;1OLzFP( zKDa1f3DHzlw`8%w8CBctTqaP=4DY2d89KCXBfbehK@EZUgHm}y< z{t;HS=zAS@tfnz+3pTi=IJdDczDHi8zufP~-{=65=>b6TDz5dH0QGa~01$jKUvB~GZi&sz<{x8J; zH_=fzqi5?083yL*X>E#a1qMc75&CCbN12u`A9p<0o-~o~JDCuK9oD|9eSJ6l#a2s? zaxuwxP@2eGC4<{8VX4S617l3OtDeWU>vAjOIwRwnQf`ye4eU{3tJT;LmG@m@`T48w zofvMTXlDA8JDxqTB53aoiI-Dy1g{%} zMC3)LsInth5@4Rk18-p?tme~T|L+#_ncqneDyU&!k-dmn%R zeRmTeAb~5_hew1WqF5}ksWy94soy}Ke)awpoU^lYg!nIJyhww`2L2K2I$L@DsuRDp zBep7IFAsyG`tO}Q#)Iv;5g{i_r6*SnOHG1=^L9jWl)(7FaIE(V3R3FoxWJ#Yd}fH- zb#}XcXdE4tEhsD$Xio_DS#r5WuyQ~0{y~EA^uE(@?8f(f=S|<;vxzaGHD4irhM(?- zeKhAP(3z0ImSN>ETVB1+^Q9Dq1KuTeP)EF38uL26{*VxQj)HZSX&o4ADMa${RZvk z_|Mw^PUnC^*wD%M!Grw|>0zGR;KMo!i@(DUu^tF4sd?_POfvfRrxDwJ7uL1+&vcS- zb0d7%`TDcFWoFI82q+iSrG+J=(<8n}$rB9@3SH4(AFnZO821F}-#|J)-*oA0mvCC% z>^2?v+>o?raq#a64^HBTQ4u}Fu2AkDCjH@~f%9|4l;w||hnatV0x-pe1>R)NypUCp z?LE1YR;>>aEmQV<;&qYm)iR}S&=+g%+u(WaFlGQ+jrv(W6XLJaFS#TFM;T9m@aa>O z7;y~TfIiA>~~ zVv1~hWM1lDx(vy5A2|_^fZUNy`t0aDhhd}-inf8fwYz}K(cb9*g>26Uv`eslXE>f6`ni`q(eyh&o z`u9YR>HW1hv!|F1QKG|fx-Z2pai)n<2Kt*}`M<>DOn?a;8Y>v-l>V!iKVcErT>-Mi zU1ErKP+{>TZ^4J%c8@tbzf7>7wj~vwN+`>X7t~|W^Q4IO4f9;lo-|6xhD{EtA z>$TTFb&@f~7w=lIVBmp3Uy8#ipBn?3C)!`@@BpkQn$$Wg@*gUq!B$vey$ENXT#V8x zLj8j+%J}r;sI|MLlg-(LA|++**3Y`s;`((Pp=*NN zVb&{RU;MxHJG?TQwxEP!DR>8ql0d_IM#T9CXE*5OGwaVmuaS}3?hA}uEe_BYH`u(X z!ermOcONYq$#{4HC`>4F^uBc6Ncl(n!bVxw;|=diU~68Oikq^WpN_lD`e(NEVgbDc zrr(0Xpq36mgc4{#R{fKK2X89pc-Cg0W3TZ>nk6G^7NJ`SFo!lT0_)j*E+!ta2T6q@ zdwcW7c%Evrj%~;q z2jY$ap3jW2jxEZB0-%-%2<%N;dqr7a9=1IrX$|2o_3gVW(HXyfZF_mHwjA{2Bn}p!@yS z`{xa-i&oLQS17%Frh}?G98u%=W8}adLJ7B>h;uvAb=OpEZzF7GrcR#PNz-U0aXj@J zPp@SX3H`{7;?Hga*!Y)#jc<6JEAUs7rRBP}9rAA6sL7R6)8&+HK4eK}8^dAQ;za~Q z#Q-FiQ~Hg-AF}p{#KY6_K7pLOWR=|qyneQxJ^nFu!a8GLnA`8~<}m^V+(MHp@{d)L z?dI7OR?v}R#c-T6zTlx|@!N!`kq*K`714kuFl|ZuVa)x}Z|~Pvzmx0xvlT8Tr4-q{ zF1QzeCxL)N6{O#q3?V*owYw8N${PW`{i`|6-5-|lZk zl4v3KIz+ldbP8XyV}D8I-zJxPX1>=7E2z;)4UWZ&pu@vVyQaoN4O0xcS%%cL~J@ zXQB}R5HX`r1ne7R2xFEk;3Qf20Ya6U0A~ve`!9e!4Q$wKkskCB8PG=}q27PU{`wQ< zAl7C7ITdg)z0gO&3OfT&S^s7Sk6}d6r~N~=9tn&O^8lgur-I3J2iWssF zKmIh7si)2}9SO4|(NF|#rxV|7c3fBf80eEUNcUZlpg45Ix->xxe!o#bM3na9$B(ee z$BIL;=59!sUuf@DtqK<)H8~xfSn7ejyYLN4sfqQ?Y-6=tW9m9_A2hs57zEdkzWqX? zBt$34bz{EJOr1yG7N$p{p$|NYaJyMIy|dTi=cg8;C-~(?O((hv&GZc&dd{*`xIe2O z6&;m&ZUy8MjLcFkVc=h{e;LAML7>TIn+gwZMMpjW0!5Z^<$q95>={HjLt3ScpIoCx z`avI}@nk<{x_GH4+DkckJS(#Hv!zIr9WJq;4r$sJWl*XhCc*%`G3Zg?*ckRrzu4t7 zhi0#m`3AILDr9SGD>1W!=s8lhkz{s_JZG&1A=QkqnK&J zsmP;827e0ZGJc?GRRs{veEe|`Ojf_m;E3u;59wa;~4*8$Yrm+Xn-_25h4Z z17Qi~5Wh}gt8u!uRg(Bki(z7oG?sG`$7DQju6093Rv(>tf7ERa#m9Y)i%R^sdh^H& z3w1}WWAh`T8(#kz*1}eLI_Bfy7$yBSZQg?>RWq%?H|3T6Gi&aG1%Dn<)m)5qnaEn> z*U(5;e5@l~M;k1eYd3|gH_%D5zDVvGt{n#xI(57TIS7GJCs~E!)7me|xg#AxBRfqf z;2QKL9rYloIZM}U8>yuNluen`lTe6tyosqvz!S9f5~jY+k6{TmLLn)0aD_8Jz>JgzW%{e=Brs*k-5+im$T^U5s&pUkj#EhPmT|I zVN#OpGct0*@0Xs7_^wA!>h>2uY<@YR#Z6B9&Rd=VfnHf(9k#Oy%osTzaWk4yI5$^pGzxHv?Yx5^b$H)2N|mrU zTBZ8)pKhzDQ;(0QGmO-k)>dUk*<@e+xYqH$Unm5^;zfzczFQ`8U6$x%19~>l@cD- zFTAA_eJlM4zo}W~#zy;(>Zvm{vmOL*vjv02$Z;e-p0s4VUQUV>ieFddgXL`PIXs1I!=jb-Bna@@SQe$Aj8(eoipn5A-h&s!ziGrk{PL1dNWc9YP z$4_tkj{B7K$W$#xf4;5*^%pw}KU6XS-{!SpDM#r$i!`?n{8HqBW-~L5b?jg6ui4mP zw6MT-pAE!)O~%q=QL-yJiNPtRMfH-463G>R)VSnlEKGCo1MZVS8#RSYDb&X|j)N#X zNM__Dg1%t-W@@-*osx4=jPMB z^cD^y9KW9*mXKl(_uZ^&WM1r6J~zhqQm4Q*<|xrEUfRKDSHyx8yhd!vmZCUDk>r%a z$2C9X8YN9;>b91Te;*c9hwz{KD7Y`rXyEGo#b_7X#dmHG ziMFl5eMsHdwV-QOLwt<>i7L;@9!<4Q@ymuPv z8!FD`KEc(jlD-I%rb0@fSFZj>CGlG=`c}S&l$aV4x#wu*V!dO5mW+VsjQDx0~Ls6H}mh`5}e?R)*3l(vAP~8w-FWTvo=;E zD2JlJ!iKyNklWyR?%N6iSu{4b9-uu^2LkW9gAC_rXq1l`ba?C8n3c-JOR|$ZusDkg zIaHEar$J(NxtZa2CQW3TMXz4FzRg0q)nOmxL_(slZM8$>-xUh#Zjb#Ak}8`KcrN3r z^;IkP@auREUtZpJh(VZKXM1tTGa5Oo6vn=Ms#hki;aF<@#OX?Rig;9=HI?20XQmxN zMp*K^&V{-fHzszhksapB>gUqKh&9j$p?*!?onQ?{<&^Z}wz7=!&>ISPkSZ|nOKZ_r~&Dmz)4{p%;RmgViA5Hr7w_RKfQnULaS;HRxTMOzCA z(u*A)h?us3Kdl+A6!rRUbnbLEr_Qo!W2G+YCOwbZy9s9FcT#*z(n0E@b;W{b$OSwb zGz=s_n`69B3`weZJf3og2k7$6o(;K_w!-5US-L2OpIX}1LA_h1L#ds?=T4^|=R}{A zC%VEo4~o7XIJnpbvK;~s0uf}ArS8az$7 zyB@vCQBxDa`_5#{u*G>~8mRSW(fx|ZB0nO>V7X|s?c5+$sFbCR9Ic8-3awWGECk*z9W8~jl9WAF*D&t?PCYy6=8Y)l`jXU4V+1;)?Ueph0xoK zsOd+TzS~Z{RLfR&NtF$B!vG)kLVX+Md8^RK7GetyUrPK+ER`*p}0p`h?;_sTS@?|Ra z>kgj<+K)%asrWW}5Wz%Li0Bavg7a*vSx{9wkt>0+h6C(MsSGT51Sb=T^Y!yCa5b)+ z=&9FXW}QO)9_d>6jQhHYRC+gZRo63mzrc!V|Rb<@|yU-H5uGXe>P#RYMd7IJ$RIR z|9fkrMQ|@N(uyc$m#fEABC&JAv=gcs$QwUbxsSV9D;2fZcW9_3<&N=C1jeQE^Z@TQ zJiG;F;&XGdtvm193O!-^ewmL02|LSnKbsquAogOH)mT+^ROgWz^K^ASQ1$ zozzgNRhj1eiZP%RI#QAy$1d!Fh_>F<-FcV{5;xf+;_{+Gp@qL*3-u&%mLF8~+E<}q zdyD?DrfFH!yv7fN>KW1I_f4Z+)lo>$jC-IDttZ0Q( zHh7XKG6gItz<-*W7@ia|Gdep+YD=oju^j)F zPo=hRfJrCC#kZi-as8-HqshA#L~C??wIjwWX;BLbnK}@pG@nyBeAI3x-CtHjHsgN+ z1z zHcC*B?Tu$d7^-`lVUZXg5t}1WGY8U)5wt$Mn)HZL5sKDb7saAgJy>!&(lyy5hs+u- z(7|7K2KBz~4fj(1KDI-Z=PeyJ;Yyl>dAi1hK4^bAb&9?=_&VOiHYdmJF?}<%k*ZF1$Zi%$qvVD z-^RjB`^WN=)_#M6ISC#{{+oa!`8WN2NtzknSegy zVgyr6*=Bf%F2=$aC+UgpJt6f*`*$aAHoUwo)q*-3T7%!75wj1K^b~AlPDl!AuRbmF zd#zc0G?g|j^Lv*k7^D@Jg*U3{?!Xi)qUwu^H)rs@)lF0^)hUB`TW-3mcGdVr+7SdA zPBuAXsLK{vA$Src=xR+AtANwT3bC|*TMbP`T|*#fSw49gqY(XPF{nW+H8VByds^)# z--^<10#KBlM1-!dugu1ZwQrk$5=f)&(c$OMm(PPcxqbPw@O%m9o2zJ|&*q}v1w{89 zGhd>QhGg@Smz-qtJ9FfY+bRA#A_I@@w@!{;th%qJSN+Oql$^lAQ9Yh~=EaB+=!`ta zS^Ps8RGjLgD#sE!Dfnq{d`w5$OK8_aNmYBE&K{8*v(C~3TNiJxQ&cEqKI7*7YEWI3 zl*?%@#mA##SE%@bvZ_!jV_R20rL)RSf0p*@#Ww5ZP_#;K=`MH99`@)_?~~6Ai9g~E zk7hHb_vPy(wxmSpT4_R|T|n8EEQ{xM>wsX8|8jR!q^N0lj=$9<*LW}D^Mxb&ve^IZ z9TaZkO%_KSBEGRSa4DB5T3c-r4x3J`i>HRt|H)-JKZgtMSC+eT#(c{5=TvsD z=aa{-uH(1byQqrmj%ZR#?%Nh9cT)k#~t*4MW zuWuSG=gFI^B3a8D3l(egSe&2?~!(mUL_Cn2=h)WT(cln#1XM!%T~GLdyGOF9(sTz%A6ST!U>rIg(wp73!xg0+|B1}sWtDY-h0F(HzlK(pRAuD|ThB?%kP znlpO}LV|?odobgq@8~KEK+YbF}%OeNE^z^Rb%G0!`CW*j+Qxd_lizaPZA>vR|XQZjo z0r+?Q;PI~BHs|czbZm#!VMdoGWEwb~Jxvv{Iaj)Ajrey+o?CAg%k;;R#=DoQOJ1#L zHYR>}?OCgnOCteGw`=bL9eSPHnxbdreh;zx2QqIC=a$yv<=obr%4vVbO^np6P2gxQ zuI@$zYp)`enos>Xjz&3GmnXa`f0U&Y%B@_{z22ySNQ_cVWBVM5lip@t2FTPY0W$^ zhd@PQd-D3cFvd0ESbD$8G<{1ER$0iRO6Ajfq6;kX`5=IBNKQYZ7xAE@amI>&SFcwWjNM(YCdn`JTy2ULWCJO-@sdxOG62w^ag#R>dOEKl#Js3DY``vja9$g(Oz@Xui_fIwwBn1qmhfZW$LGk(Yr8~HZo za&YP9hbsFtG?}qg~lHmsOc7N zMv{d>1+N;0MVJ?}ROLl`{RrFMEdEqfgV>gyylkMR_Oqzme$i+bP`q2I8GrRnH%{S?deOV`* zw9cf?LC*))Q;@GJO3nJuNoqloJxvvA%Z<$$rPKy*=@QJ(?CC|Xtt=yY!Xm;JG)BF*rg$|Ux7EBB@^~rV9P*ak$%!!}pCJCr4uyON zpYT!mW^`O>p2fjrF{KxA_u@UG0nIRh1yJ`yCrH z#0w`gf4*veEKlQEMX}^}oZx$~bj&j!=080aiX0VcNaEtX`C} zKn{L6)%yL@*soJXlWx%{dC=K0J%;?`o^X_)Q8)LY>_MFC)o{JlS}+(vo&A!OH)3t~ zGda@wK3Gzq3zu%1OHeoj7Ni=&fXtK?Zg?Elv;OJ^&u5UT^_Yt#*rjOigRRdFL3geC zvAA8Z)8`_Q34cvtluZ!~X6XQyN@w6+^~9e-Yev&q(fG%DsgrKSA2Q`_nM78G0<^`){guSKq! zu;lXv>2z`XfO5Wpnq21(z?GWsGA6l~coyq$>Pl!0ubsCj+nVfDYr>i)$j=sXj_n2S z4rewpT|X9orY0{o5Rj_~vTf8!A*@swTzXsTiQ2xV(&?n@$apr9^s;_L(C8P5-1L@` z5_(^74BxM(!M)0G{Z0y$Pmx&YmA29NKQ|d`Xj(`%@<#cH7WR6}^m=_2tt43R{CU`S z{s-ymYIgV?xeq$IWJRWCSD&ZJEp1VE_wNCeoUXfkxvmT@L-hGn_e#r%&ooNgMm)MH zYZHt3C748sCv4-jChoN?a>8WC?v_rLIp2^F{5=kf7%h)S^g5faIXU=(pCRGcFr2@<<7&cyU7z$m0DW8gfhV5tl%?SHq;+kKU ztkwk6vJi!zq~sj(a^fmq{sP&Ne#)VwmUCZJl+rH%(c@dV-3WRybA+PQb#NtuQ1B8I ze%LT^{JN*aMn4(=)|*-|1;`)<1ii$b12%IuKMJ z1q#y9+F0cyf`hG+UV$}-TuE;E*)rnxSy=ffBZ-V1%J_@$p=m^9c|8Sj)4^u`D)_{- z!%!zIDsHZ^Wt0Je#!)rr&)*lgH{!|`R4xvj_;K)y-vJ$IBpy{MI7V?ZpyoRLZ1B0h zmU_5Rb8~V%Qr_~s5j=S#Njn)?(UFI|)5z;=g?4f;5hobEOtQ^WQRX18 zjgj5AH zx5rOSA9|QLBOJ`JLGt$1>2I(eN7DXzWukrSj35lLWTmYZye12%6K6*gDwEx|q)I!n_Kmv&Lz9g)^0o|7La4XAb%afU zGQMtlCs#*-5jk!ft78%ZoK{2;dp};t94|A1RwlSL8CTFwK}ex#nSbEqmqTy_}l;-e!t*soL!cJO4CpOX+84 zar48zicJ#7{K+5%vK-|$icg9t>Wq-=5YJC3mhu(nwb&35w#m;uv<^a))AWu^CrJbf z5+aN)`I4p;Mjdbb>#rI%N+*O9aWp`5Egfgm28QNmzX&j1hW0S?Yi)MUpvcTwG@ZIjZ=(inoi+tFE71-enB=`>P&J=38#~#WwXTCtr^}DMf1iQS#6`ij zSu1x_f?dVL;gVt9JP*5nfGq%Ar=;|A*OKq%!L)}<0=bMimjZoqCxCUL45R^2I9v*J z37z+@7F!+_V6??%`2Ssq41m+gvit|xW9A4D-|d$F5AX+w+T}2?+}n-!$uLs~vcgCA zcqOHOI+Xv9;FSXGyTkYA$iyw#p2}XYNM&{c;8umGCE@cGA$JUzJTEZeChK`G*nuad z#K)%v@?5e{X889EdEZ_vIh)GTU@N>OB^84mFfQOJa2cyxE*PPC&;uwf$Bs*GWj;!- zID;2Lb40uhmH9jlBlRfEH1M&Z0$j8?-^4N z{v5RL;L>T@E(&VF)&h_=z~M_sx(7VG@-;W|FcQPGt+Knxf1^@3-y?Pp-Kp!at14F&u?!0x{j zzkGhlDJmSHaIJTQ?uJK=(v+1-_AA)O!R+6NmoR@Udd+P5^_bnC{POA3{)0qGL!0$< z_jXT0ejhoYygbt8UIJ6+IC+?Ik2#F$Jn$xn9uqxyCEfMofr=+2){6SsauSD=+>#@_ zNJaEkj2}#21Om%^B6YhHb2xy2cwk!rJgbJl+EWY3>9EDEUJ&v*$_!y-lq>bM&6dR!3a+EZY zUE%SZQL#}}ROE@JKYe46aJu)hh?TYBN%?_1l@1HE-!;7Ajy+~gvqsDfO+9O1S z8({iFm=$Q_)?fqB;V#9cix=o*f|&^>;BD4f$DHqlDvS*q>z)oZcUkU6_gqJXalMnp z4HfnqP~egikIauji#Bt6L;6kpk$mo}Qg<%BrIRL*Vg!c}cf5*3mXLFwAJ6GEH1k zQt*>dif_eY*Kp(_r+Q8te$yu?NkR1hT3D1Q*~KuFSy=&y zPfV=uZazb0Nn9qlcTI$7G(%Klc_T(^X`dqFednGGL-5!Ky$jXYq6chfIShu0C%($| zAa<=UW&wZ@Qd5w~?JREqkgwUrv`8*%KEi3HIOWs-1nO zx|;)t(I0MhcDAIX?0bxHE6hZ8#oj!se|uWB4xR6?fNLM`o8zXE{8^k?rC6Pz04VLn zhgHU25-}v6Xr3e(_cgKsDiZ(TP(FGP*(Xf3W;Sf}PIkCLUHHBL_JArD;m%wRNX`XYj=rx`ZZ|(a!MDsA9Hf3pz1@k;=D4=x_k37h=m@@u;l-9;_psR&a-y72qU-x; z#?b*$u+jpLG!FlH7Z2BG$P zmg83)_P-U+d2&SRx0jTm3p|5`v6&`|ykn;KV1_k=B|G(Ah0O*5!>J%5!+_Z+Oyq;K zACp?7sE&fIILlTRpL=~dzpBt3crlfW^Q8TEbEZA{_jx0|Ao+SmO34D@ebJ0_2`t7g z4?On!35Bl_@Dq_5G76s;jkS#4oL?^P%(od?T9zB9vXoUwNqBXohgJwueV~%IOL8=& z2myk#l{=zu{2whKTgwu#T{7anM5pUT<@ar z$FNxNEC;@9@*de%Kv{KOs%mz9*aK$DvC>dNMF7Su05t@l5C){~C40mbH@l&()r_C> zJmy~9ywI_>Xqlh%U1jcwg&e)yvj0bkDFgN39#W_K7wqWk+DFz(+pkgoQf&KFy2aW-g3${4J-RE z*47G1DHb(%FItyFL^!nuRlo(t@EIjI<Yr5@oa>$UT zDrbWI+F^~{gG$2FFS`%tZGJc(^|=&=d^0nW#o;&CkgMGrQRkr$WHbS5yAqMAJ|MZp z;eeqKT+|<3f8GbVb|7^0WC7!bviJPZgQKlSn*ksoZ+*__cL{9;?iC8i&z}X3RtV8W z`Q%mlaJQH?3^yTziC^R<{RW!764oAPHP2kB|1K@S4wM%_Js-g3iJIdT4Urc}eA&6F zcONzP;cML8)meAqMN~zf7@C;O4-ex!OdiAq;33(*C>?S?Fe}+JFv_A`Wda_98gd&O zHVs9>)ty$@?&V<~dg=&EaA6kMgqfQ0{nxMAV-3HsN~|dBKZ7NCeX^ zXjfrk55H1DAMB!?u>B6}AuTK53l!8(jq<3^-??c`B`1$!jskG1vx3cZvu}Xf2JN(^ ziV;FT_@4=eB*Y-8=eCorpH^8*FO5FF{0CG~gfn6U?&3WaID-(xXQilyhAYz#;XG)( zUQ$4XI9!6t_7%JTdsn0tbj9>iPy_HOZi?8ny!Ey(eBq)I(0km=g$e$0OfTZ=zz@t9 z!#RQNwOM%uh1Mb6z*Yrtfh?}6B}+b-t*Y-5(Q!&SR!ARs{Iv#t!m#FcU}wZ`{)_%} z&9%cuH!CLH<94Z1h2jjFf>w`Blf~Tm0V3N|40xESu0Xhrh2Yc_^*BYSC zz_$&9u_1#GwE9d;wokg7YyI=NiVPU8}LWQ4PZ zy3hbA7<~rQX}y=?Q#4Gn_&QTzo0e!t5sLd2a&L^O>=S}ddvAQ+)|mY>pu&vBVV_{; zVot`@A&NxFvIG8DuGq$gkZIv@JTl_QjJs49#L*1G9_QwYPXa$_w=cyzN*1-Jb-qK? zQ;Mp5a6}F10mxt`X**sav`KW3_4=&EB0}5o9OURp-~%*_k`ob_kR;*c5;C2lZtgEv zq~W)c)zNu{8lv-Humz}rE(~D-)2+6~dGZIs^p8tca z?~~1c`L=)jF)1t=?Gbjv{jY!d*YY?u*pi7iqk8u?|6uw5`6`bNG(;P%Td($fcOhC8|P|H08=YRXlzxaeC11ynLCW!uP zEC0!od-n*14fhCc#OK3)`yYP-gQ$QdxkZuPe;x3@@#CM!?FO3;BR&41{@+>l&k{)h zJD;XDE@SaG!2KsnU}vWk1m+Z!V!WUX|IUg3cu$!NTT=2XuliqS{I74~{{K{$uYV9m YpiP$&c;T z&NSt_r)d)yHCpWhor4Ns5oCCyvBetruc2)^_m%Z6$$Q0jxUrQ11>|vj)hSnqxF<* zGOittT(_|GwM?U=-`Mv$pH>=ycr*t#ILl8=YDw^)yS($vHcwf}BD>5&QaZh&U%?Gx zVM0&8Xbb!fo0eQ(|Ddw06k?O!glPB*<46Yjjcv{D)uaUl>-?c_J2|A_`yijyVlwN}R;!4hioW-)ere3h@;8GFgBZq7!ik`Hzxt ztoBZq`Fw^iXG{?Ph=eD7;O!CrMo5se}zo}AB8rEO7IHzvsc~&YnF;GvG7f+`F-nG zh9jI+B24&-l_oF!cu;qpd!p9>Aul0t>x`j=$R<}YfN zFRwnlpbdJtZ!bDedf7?2!hy+&KaYAzGO(7+ze1NDc$8=#Ff38WCSE0UBl_J)m~b6K zWrAWKs<}KFHAallen-Y@-1WMS-2V5%FH$@bIDW7wqZV#$#@hkXx`+5SHw94>NmrW8 zb%S-Giv377jy;a~V0E18`(}YY^|7GcK@x)N5kV+;_tb#&IFq^tk@ss#x4Z#v0mbk_4zq7ixitu?=E7Qxn$>fEXC}vl-T|=OKBs3HXg+f|(C*t-mwi}owiS_v&Z{q8!1_%tA2^o-%!U@MNT{AC_;m@3#^L$ z{Kn=WS?AwzjQBHnYt`w<w$o7`rPvRZLdrU7BqIQr7k^w<_l%mMA z_U3?FqYYnqZwe#X!2`P@boH8n1^OI6ZbCZ)7o-2xxQJO3NX z^T z5tb3E5o$@sa`bZXo5q6(gD(d=lGHfBRXv)Mn%0aZlSIX=#YUR7RUTD4vzb+y)lO9j z7Kanfd3V~uSw_X!868s^S(Tz&Rr0*VnOeg$&LrOC-n4fNO`-{TR+;@HgX4^o3#D^e zbH%xtTR91NTsoy64(oIYpBSmLz5i<6^}LI`ORg)|psPc@1F<6>y^vs%XD{I1{!Yl- z&nNmG{*Le_?L{IIIg$oa;S0+bB(GM3E`rux2 z1E%q;L+`+YUkBO;*G=aJlLl@EYzD9g@DoYj`RWUoA5}=zs#}eikJwmPa!)$On`Ce3 z&{xDI#0^_EO}H0gOma?2Plgv;6{XE>&)Hi)w|;ALFgI%b#M;TG-==g9Yrk=?Vvlo< zV=nXJ;6en-3N1v>3kVMAF{l*nM`=en#9GDLptR*yBG&kJ{VncWX7A~#a>~{z~eeF&0%yXsUaSk zX_+C+PU|6e7Vs)LaXxXW3#+^HD?Q;QyX&XDqUlqIvpPBl&$Y#FqDI7~PyD};2-Nr#ek^Q1WQDdID?P3broE*T=7|{S%-c-g`V65kDWNi{*LqaNl zo8=^ZND-(OUnQgaUbS(vUedoGFCpdDi#bE3VUx;qo8LlF8}~rv`~5IYFMf%a(P4IF zXLhV}taP9(t=ze*(tp@r&vcc|osH1!$6%5mWW;)MZ{I13+ro)pOLIVnz1B!~x{?2s z?zD3Ap}Ez)ZTIOR9t~rWmT{x`V#Y;UyH5eb_?z!|i<*025agv-sJZl*(o{BKybt3l zzRp`$CMLT3#;>(|qeGcKOn3FZ?l&hnxFqy7MN}m?rH%D(^(Rs%W(!eOYfE2)b37QG zY({3?AUQ=~^;Ojh7k-l_FK;aiV~c&Hel&V6uf;d>piG9my;hn`Iax06>4ByB25NiR z3DvdYPAx$jY#VSBzqO}Jy^DJ<`s%k^Vg)yv1HOmwDP~;o3pd=un+mN)u#LiADjRMp zF0N<9MM<6*{YG30l;*%{k+iX;rmx%*3g6|o8nFE9b~#*6*|*94&8p&>L1~AIWYITk z9vMN+PZ6Jn@(xO{CaWfBrfP@?or=o;)E;cx$+zs6a1}E1mbiI!KI;n=r@c|Y`?+Tk z#qONa_kLpWefII<&T(#O+H1F*9qZpSs9PdKDFQ=0z9;@mfj8j-_>np%4WFE5)*R1q zFX<(H-5&1DV+KP&^slHn=8r^(8VtHRrv5b2Spz?GSlbeLAZr5Y2x* zU%pMZZ_&#(W`;YYlRD)V6nXwvsmMYwKYG-R;ry^VQiQSz0*OylHqC ztf)n@b8B((oSMcSJ3aFL18v3-Z$fJF6!7rod!XAHt8BJNlTMRunfA_y5*(lV_{#gX ze4*b!zkRM>mcFwC*EoX)$M_nKhp+Y{&6^?rC;o4SN}r(I(iZVCqlX~Fsgx<-c2yF> zy+=tt=j%aBUd0y>!2DHGA}U8+;jD&FjgOo91*Pfk&MpF;Yy$pBe0FK6w!Y<|U;fn| zF&u$ooS9-E=E@HPtullK4K@psE8*{3V~38n<;Y&x_K5-x*gb!L zpTq>gAp?KC1P;(Ig#YM`qWkN~f1JZp0c~)?%A(TJz^}5Aqlt;FlewL9KnC41aN(J~ zl!g-=93D07fR|RHIs(R@viPL#tSlx$-vmo(1ZzOV-NI(gX0770H-!4&IV*4 z8*5u99uPmpV-FtS9Cn$Rg6y%2vlTyux||}JsGXw;87I>_rgszq&&kNh_#BN*d6dK? z{<$6ai=V>W+1Z|lnc2d-r2&=mJBwofuWs?Gd~3d>_Pwe`8!V&ki~yJ$=2x~vH${^VJ*xoOz)Wg zb8O&NKG;nr}}@plZE~Ny7j*`{XcJ2 zaWZifwX*@9=`8SH^7`kw|Gn{_8~K=Fr2jWo{N?lGRe;d~&-s}DQ)mLue+>O#1LR0# zA*S#N_yx4=@e>1lzX1-|FK{IO;71VhhJzD=lNJ;H1cKjNaC0Ww`f+%T%)KS_`I-JV z3OXemap~`Q3^VbWT@HLR*shz43qMls)(%qdd@p}4G?{IZq?McTO*Nyh5gE_K#5qxP z{uK6yi*}M zpT7n^eqQb*TDf}luX>XS9r?HX&&+t7rT#YrMCMJD?(Tm_BfLNUE!w}BFszFc4jG6= z^1VRNzoQYeaoO(QF%B~^6Rs_syZxBu-%0)R@>Aa@|Ax(EpIeEZqUa7_eTyXjpM?UW z5s~?d@L#IZ=9@Bhe|%}_m~~ghhZG+Q>6_WJGw9T&dFwyC4{2%r&ZzX@@NnoevZZ`c z=vjqK10&EcoBG`ta{Vm+kLv{68^;eljI9ABR1KpRQ2xDJg1S3}Ed`d9qpN5lOee_1(iUjDw}ts4D?bbW9S>Yi{nC z9|_Dq>aSx=A`fy~`4xux;@8K=TiH=~{bAB8JA0Z#LugKORskNK1$+nZm`gqSXJ{Dxzd_T2gkG^)tNqJ?3*4&e z^&))*Q?kOHj=clDamM`mQu5L%KI6XvJyQ!xsdImSYN?Y(6ZrNxpb!xvL#D+_c(0V0 zg7NIo7f%6)b9XADnDhfCixzE4Z^nq1lTR=n#R8x9%sh<>{7X?rRYkUUmm@~&lUKFi z%Q@Q6olNuh0sojJ!Dn>>y;xDZmcRB4a0R_2sOYd5LJylhg)MNHy*u*r9Zw%N@lfW%JDGieQ%!3p(cHCsd7X?%_!$6+n43ofk&sVO2;iu zowPiF%L~#Md0cH|ZxEDYm0wPR`z3BXjDIO(yxnDzwv&zhA{i7=5x$2ElYZ7y2K$ei zP4Y6Ts6GnP;$fNci3r1RP%QNwg|3cmQtnR>Vn3N@ugCc~WBPaHm#FD`S%1JzDIV3;%7p(K&N@Hl z-9)+|$GgFHR&HP!HA*UgpAKD{54*&*Wb-+iLh+9WGNXn8KLzYN>^V< z7uYrFSQDB2ReHpiA6w;}C#}-5?ytyS@9bkiQyw*4-vE)}g>HU2DkK(1r9?e3t^)6` zh`iqDPh1r#j5=Je#uRkbZnvQlGP|cNs?_YpFT}(o?RMmt#QxoT)L;4a_Db(eISj}P zK&`m`u+nnlccoOr%xwPa*GdhR5qmdRW>pF?5>Ey0sUGinsoH9YhrPDuxY=ozrPHm3 zZdI@M*JcJ{^)NEU6<_kN+J36W{12{%zJ15dlHNg<8kbb78@+4PmjQLbsd=6#m09E?Jh|k}~_s4sZ#>A*h zoJr$}{fv9u6R$K{+wq$iBa}`z=|^2QD$=;(Y+!2@fx2w}zPoC*Q?-0WqE7W?UXF>` zY!01w+{9-01 zc+OT92$1v=@(}m9{wg%-+u;R}I1{P6RxnZhQTnO-<5b855b}3+Dx?FJ>1*aGc7A9a zYrK&a{%aTD5HbUvlT3KPTWt8T+;iWt_8t;!g7xGt!{ZZ5>!iSHd zh_25SvRazr$R+W_QUHMnQ9Pf1_9t%6t+(s$GVEL-@h^=+%a;f%nSR{W4X@@#PpJ>X$_Q4u6|GMy z9yKWX`*$j86)WR8??@S4=^ts{)13b>M{fBnTtU`qPy@~21@kOtnIUi;*sk5PO_aPL z0{OG`v_0V7=D&93otarGo^t zvpDsu9~JW+uPl8=f&YPUr@>Jp*fjFW!w8=iluq{t4SG0YAmJ)&YMWZ>H~s#f$;kfN z*^}lfInh_^Hnc&2h{IHpQL)^o^3&lAZFXV7lcuyiqQ7Et!riv9iN7%l&eDL=e0Y4= zF@8@UbJV#TQIyJ@tF)tx%&l7MORPuKqrQr;rWsm#Jit!Obo1 z>U)CmyGvPKcIb!$lQ8(Ns0^Q-xmES<;HO0|ZU%MEB2I<_*AX>;d0Yx;fVa>YceGw@ z-x+WH6;xv3=ZO4y``x_MbuX8a@MWjR*^nUAYhrmNp!e!3>e5N~N|PKK@(#$uEITTLVp);W z!PPCPbOAcI$ey9!u?8`0Cap1;iAhN@N85Rg_X~C*XuPXi79;-nmv^1M@dJ%s=rp&t zQ*AYmqGu@hOrp@^*>aO!H8shw>ssarQ?7t;$(pa!nkK2i!e*= z(D9YX_a=d>p6V}PIWj;9#HC*^DZQ<~klz08m55RLSEuy7WAb~SxnD2cYZOtWrR9pF z>drrKpy{q}LT7>=jS^r7MxLTS#4LAaa3K%^1o`2XEqBh&T_C$YO#g$dSILK+FS0Nj zLxQRLVFEWrRXh?|l!(lRLZGm}BIf}7 z9PKAT2>>Jg-lG6RJ)sDH)E$&Y0K~U)vG4-RIQ)&!ks;Qx2FG9iVUdAWMm`}j^Vugp zlKxrfE714Vi&Plj9q`CNSZ0cNk1B;J1$ZQW)~c@0;Ss$kgpS&2(b`P^+G5Sm%Yl-o zn2krR2LC7s3jo&*-#t$3x5npX@t?vPk6JH827rFV3XK^$U{4MOJiat`#AH9%^p~xG z;YkKXkJ_IEYdoqS%5NAAZOe2(E2bIH>VRb8@Yv!9xI0)qrY5&M}n0kT&{`2LqE|I3vB)s+8TKL2Y|{(oa=W6j&b^Xa02?L72runEP>=&UR%X=%BM zG6X(J14~H%81W@Jh$S0eYOkSZ z{fjQ4w0wNk+1IB}YEfNc8xDG|>ORQH$%N@fN=wU5L0I!WQY1>}wyTq+n_St_r)>AU zIjJGl$vf9KNO!);F?*ptWE!;(9<*Au#jW?uu1UHQ6}a{Bl+;SM1R0hZ{9KbogdoV0e8Vpf3~%kt4ovH}I72vo{0ZWDO-S(FzrsYR*)ilunt}Q&#uMzPxCrS}n+lHXD(_wDXLjo`af%-5fMO>{NF00yR_;Hw#c`I^c6quXs15;YA~Zk|}7^H*6a97kN1m{{d`=)MzPQe9Ga-KMSB zS*2v!eIWZ!p51sO4mPE+v25#ef|;^I5*^j*EHhKx)6;=R1P5vX=6UJacvvg;Om~`8 z*zAs)`?%e19{-Fu4O##d5jdT7GEA8ab4fNCqD>_O9XGe2`#d^#A-I567PdLT&~7t; zl~y6WqkkPOIsh0Y?)T}EfBr0p=ugfZg;L3Qt@()~Br`2l z%}Xs%I{+it=ZBy}i1u_0mdxr;GbPVt?pcwJ}OR3VFVugStH5 z1EEHa_V%zAx=ll5P+knt-Y34W;#06qjR0WdJiDHEXei=i6u zFjW_V1N0v87uL*E0F)LBDF)yp*>>2d*R8bAl}ZirmP)G!FQ|tscdi2~+1Dar%IByw zCN+++cK$N4Xu45H0{JFeG#ICRU%lQWc&=pja?vra*RKA-=%7h-A*ICMy%}BF&>$3h zNRZm48@;|IjlEd$W4%v!Vf>29d3%93(e?gNby62E>*x|hKwE?wLd%T<-*JOwVes`~+>8R`np@$wAosEd#2M{cRAhb(ZU;&(G!N%IbnarBa zG8euF7}+1}ep7?6CRSl#iaH;dbXA2hbf@tzvwZyAxF)S$7bh$v+$QPN_7_Kb-|SxL z^=hih`ksZ)E?ViW$G2B~U(fnRiuWv7hm4YgzXMIq5E)T5p1w$LcOH~a4EauYb1 z@-21_?#lbaIGb!P#i;f!Sg1J$n}}XdExAZ|nAXhIZhN}Jg8i6R_Q0e`584Z1%EX8G zk`ctRFg45)Ry}0UeVf0tXoL+G@F!_eFn{>Hn3mCfuX~3$g*;+1XH?Lbg2A zP)f_3d54rtYv}!x#ry8=RA9PhQn2EF%-MY5MiKj9-K1haz-Mw(oOViW1iZWV#WLyQ zhjW0A-W#4YNtk!&M+j^`4r``f2rw?{`iZ^J-Sb#iE>SS_Lrk7``F44Zo1?wmc7w~Q zK}x~RA&#-He3lff>p5~S?wmU4cJ~4-pK(|VVO;Y_>3D1X)BT*Au0We^4qc!q?k(qB z%zVZCIpMx?b$BaQl;*2*x7#1tjXB%LZ1k|_2o48V{wy9yXz0<>=Y51X3 zl(cGk{R!#1Q0qwJ-P4#jm4on6bRi_3IpeZiSquV^12_r}N>N8t*(`mHK;zBniZheD z^4N@(ax9&LU-UmrXjvF1xU=Sfs5YdFxpFu#uCI@tsWKB!?cgmt-}a;pGBbC>{LfXx zT7KI$wTJSuz&qi&iy7D8AW3Ji6Kr2_Jn!yvoe_>ACaSX;PFD?T08=s2_wU=8JAVrD z;5p~-Rnl$Jol?dDgHj*E|6U=$8paS_p@vy=d4y2R#xkckyia95UEBIC5L)%9wi`s( z7irNc^fMmXw%ywvZw_ga1q-^NnX?MzK7kQ_*0c{rOVKHM+Xp8V!*z0#$f4$>)a*Qa zHz?7H>d>be2i`S*qVEN!n0v?X6@1(Sn{}7vD`p|CFGmlM`g@WNl-F@^A*Vaw0R|#N zNOc@8spQF3pE-ViWs#|1rY6=!~WwJU+aih zNFP7^%bRt0VxF5&%-FF5}UBh#eSyMDY^L$pHGdAcKs?iIXR^sR8vOBzpVkVQ=VsiV7 z7waX%)QVgUkRXI#(a#zn4Be^M+089F1+IG|mwPS{dFlSBFc(4>0Dg%=aqt>njoS>; zF~lP^O&U!}RXFov_?(w6oF|)0b<}hq;M91R`W)(2VQ^9h#?fb~U1si&URxnCGcd3e zcxMVPn9k7>B6Z&AXz+aSPFifV^t&)d^H&c<2b;2&O!*W=8c&%s2pQfnfEP_CIEo%> ztOq4}=^34-(yfzW(Ne!(un>fK?=NI#%SCUwmgyxIy@E9l8z2I1?G?gfu^k?U<<09L4Ik*UO`Z*GB-iwY$<1x-L71g{Jqw|R@}u_R z!0w*3>NW07r-e{i**y7Fh{ky)5VzlCjrh`Xrqr`!Q6=XxV<&W|xyCeq!lAdQgP(-J zMQ<-X8q1BM+uHC1u$lvAg@M`BOi%RuPTo}joCm8m` z4BebEwFOSTEzY=nQaI7b4rh0JIV``YQUqjojx=+;3BaiRH$0s373WwTH|Kfx^N@rs+JHj(Wn9y>+Q{NXzI>VQLvn?8>sp7g8!LC z2Y<<8P5;vcyG^^mAy_0WlmP%+(OPNVl0bR^PbzDg^%!}RBnG4+WK&9s|P4XM{ByRPEILqVPRNEnLC1A>1T2Y|X49q(rup9YROZpNAEyvo>( z=l6g+;=X)pYcWVq8(H^KMYXrR{Z;&j4CQiR)!%5A%jiPyxpb<-kneAO z;~n{rfK;>VM!~oH3;Y-@C7Q_Fb3sc4)}fTvs^ih!Z^VwYDmH|ptQGSM)`c~Pj>u^7 zB~>y+(nm{TjEF0ix%^2IWWb%s-mXU>w!>HnnKN0;I{75HnHN`3d=ql zQT%1N;vm+{Nsvl47}t z0@dPHml?^<;Z)S+X^EW?tw1qCYRdG$=v&{yntkWCJ)V8SGncB}XJgiGqvHsquH8v0 zZI#Vpm8r&6mbf*|#27y9-p#53q^^=03Qhs29|0$%zBzIs-xT-GTD`lgvU?$P*031I zJRJ+w?Yq@yQB;)v>ssAOpNXh%O^sdqmojKoe^b8$azGu;{QMOTfUxcP5kheq%aU35 zXQQ6dg~gXTPBHEU4YL$?*^IqK`>^ErVC3a~cxM--MT4e17$0-xw(IUN18MwDa z6{#u(QWLDrc!<82_=5H;`;KUV)6WzLeP?c7s5%@Lr+IawNgCp^STk$@+hGHC`ea%K zcD8r%V9ATpK+d94LlgJn78Ssu|LJr6dMdKvPFc^n?J)UTYo!t<*#A4e0N{TEE-y{$ zgBV;DrmBU)?pxY4Uzx%co%j#Lx*Z7Uo+QvBRK@Ye(-uOgH(qSaEU zS`BP6Q!0&ZEJ$}HB>3I_+Ed{8%Z2boy}=}{Ga)1U{b=n&@+X_6{dSVEwy>?z*NtV* z{k9gpdR6A9k6XL5HG}!e^MP;&%n{Y*aDZ^xv>dYFYuEm&SNZ6B+WnxjrQ_^}gRkno zY*Z3yhWoS_L85ta+)7lI6&4;BehJH#B!!YRhKvH);f^HTDu*x|sc7${sDZvIhX&`b z#$Z|5%&-IW>eHmKs*`5d%Y+DO(~Vk&9rxSoo#!~U0yi3J6X8XlJVM{EkUDK+}f-V2A zI96v6CgIdoW3y|U%8ys^E*=%*{zN0k-=MQv>%*nKdqEmiGG3k>QMR;CY${e1(II@O zHq%E`S{QtJ>F0Cvp`s94erUu)_tSR_%QoH-B53hiEuHes&DU#oU~>7B{yvjAehk?- zpFbBvZ@rzjQ=Cd4x@*tGtXqJ{NP>>W>a@25{nlRy4gsX*p!1;-Ms;GW5XDpGB9YW{ zHrt858P${DEMQwYA`JyEbPP)h=Ih6)G)ho?R)p2 zt#S~EqO1O{BZ!sn?&R<+XG#qy&T_!zsab%Q5q@*1D^)8Zs9y;2Tq1o?C}{@)^*n0C z!v#@Vfswo%b-E26`yWUlN2R{2H;UIh3?Znx=DuAy=5-mz1JBU1t@7^LBEc?oKW>H~ zg12sJ4)3%?PY5qbohML==j&9IxYWS+5=*oNos>X!TO1Z0lzrKl*i~L$_wDv#%l1{Y zoEx#Tk)62mj|+6(XBH+!H@sTsh=v8SbQh3eswNLLHOV{i1ki`c*q;~Kb{)Rz7Ieu; zRY`$QnH!Qzdv^D0cm4WEhrC8+Q;b~g^^xH&Odf`(?iUxx@$M*^&la^xcE#1FtkO|= z>n+xp(>#uAZ9y@t{O@`uz_X?_!~`Z%{f;xCLq9VN%U?Eg9yqnA&Vkl~mmH}-Pwg(4 zxl&X~(f?EOG@l5#c7&&^3xGXojX*)<2C>Xft;ye}fDZC^qAtyv*G1+(l0wQP&ZxGw z6W_lKsk=PT#$3s4rX_TOz_S#^px9P5;K7eR2Wn5 zZyq)ZG_5DFlO}U}fMvj`@vzpkbo)tRxEbQV?%F;U#2Nah(q{~H>4sKKWLgGJYpLrd z{ckM;7Z74w?Has7gc<&(M*yH-t z_6(f^ywERWVl(f1=<<|#Pi%Wf%_nyQ>~osl7Oq*GWsr_Wk7W&n=@+0Ob=c{e6YU2= zg_D+eoH^6Ma`_$=lQLLl7AIpt-0q^Xx-L5TvFFeOS7bQOZ*2b+>8oR5UW8SQ&4&m@ z1>iS%tRCJbGdBnY#HB4jukcMpP)SXV(+|0PPi*qX$O6#R%;8Z`6}{{$4A2i!(x(BV4^x(IYMt}JnDQXMFZjUdHsd|zNB zFh%0iuX1vwf7Jf=Zid)i^rlWNn4o-Fyb7Tk`7#uUngfnmBM?jkLEquS!b`9H#GdO; zb0DMYs+$~6=W7MC^4-tJj^+v56eih-f~GT<{P8>c)gaYL2E~n+f>|nssNW!ig`DhR zPrHkk93+ArYP~C;`%Fq&zAujJ|B)8R4-GG`oNPIvpxpWhb4HJ@UJ$eh9W8?b0(n7)9!aLi>A3PTyNM={HZ^^LHg0PWTlad8ozLc5zd4RrAf8piUCeqVOl(R;&o!k( zd7ZZ`uBP0C8lz>>`n}2-zpQM9yxUn_3QS_mwW7%p!2!M;eDT_Xo&tn*r-u=VLKYDJJ0ka+Eu~UXE3sg zpXNKHQZt=?%BXLU7V$;&cRZh&pFaTc*oiDG$f$yxD`D3A_gN!H!T5e<*VC09??v+kt`p(ys4}Pso zSGJ6j3kRLIu6!i6TwiuU<2bnw!>6xiKN8#q8C|o{eiBqaHUuLvS~IW^+Wrp0D90|F z!w`5Y9!IZjId;*B&MAR(GoNDT8dWa06a_{rSYS8b*Lsoh|JE3ztMQcm;WT5 zw2?D*Lnjq-f(h~$UBL6lGo_7(S(`tD2+~)@t298ci2bGx;G8yMS0VsKl={F5qi`jr z)>N^JKzC_=2o-z@ZZ++Ao(fu_3;i0=TO!E;a+rGJAt$0e@eDPo<*3*<=3^66Idm;8 zR?ef+-1=yBI94zwDAq&AWW%z_=cJtbDRY-7c`?)Rlh;!M-vYV%3MT*DW~Yv<%of|R z=lMC$<(=%Fm!v5d#qnf}0qe?|bdD)ysvzL7?p?47Z>`A&UR)jKV}@aA`y?as5LI{E zCA&b&RnqJjR)>kG3WGUgG#`#u=cT!?+wHOyy47@xExG|`HX8$xS>F6vaazBWUMVa( zh{n#x>SV9)1tiwix7k|8*Vo0RhkCvT-=C0b7mU74#$WUimlt>-jyGnE=kLQH6Lexc)-`wcDLSdxlo=Bh7O?>gmM|7{geI{zK{eowHT`DFWcmeMYq zm|fl8aO~a_$O(|fjpL;Gv0p)%%@p1bx@pA{>V$WUn%#!zPxd>aVvs%=i(0G~@ z$2V6@Encm($hsM&6gBP3&$teCFcqx`v&4h~_85ik!8`5>4bwC_L=MhCLgvz+@1 zjTd)z4FW=z5BGbVf32DL2XK zn0O>m({>y!)(8&+w=G#qPBmHjy0X6;0R4(Mx~miBp!;j+%dKvvkth zz0i0zz_7pcwFmHz#v!kU>IFI&F}w!Q;>`V?CKr(!_=R?{(Q3DJ3Vi6=@XrmbFT$D@n^P zp(zd6jDryK$1MG}bbZ@Ys^5%Su|Ne*O*Cp;*9NKy!1qq_g*fu&WQ##+y-aT$!)xzV zlq!NY_E{R*6T54DkDt_M^#7SMkgp*DwJw|yvL!zjHgFi_xM$;U*1xw~ppXs^G0`@1KXeXHv2@sh(@pY9!Om z*7WD$O+wvTB!mPw$!2clGtVXvimA#!bPH5sN2tE;=yIsR&dB89)O0`RL9@PX@{yd= zu_1^VF2K#z^PXJjjnAdkzO;Dt8~s(0oOK0U;GKH!%EX*o|GnT9<&ROD>L*{4+;m<1 zp37=(#($U5b;$p)4g9|ldc#AFQd;$WI7)i1r9gpH=+wg$@%L%YeIVqLWw=07i+=x@ zf`80uPT6(x!jLB+F3hV`$sW@`d&(aqcsF`Df9#z@l54hsZ?4ZPN>j~u2ztNQKJHp% zOMAVyZh9BmF^lZ}@n%j-hjil)?Y+8VSeTA)`gQwjG>~8^E(=dpK_|RgIWsr)#2;kK zi5JAN8lv;Dv$YyP9L23xt%|=PnNV8=jhD_slveXv2ht)&%WGgki$2D&-sG^v@1b;V zWUIyS`F>KNdF`!zk(0qeu(ofvfZ5#5F2=ozrgQS1(}6LB7*&rta9%Bep&M=0NKN06RLh^&1SsWc4UiB1i513ue0R@*W(DO(IV)@kVRNYIT&$ z)?5o+4JN2351W*I4;;A?XV0-w^;_;qmmJgR-;~;?KZT5)K_W_wIs!%~6t_x>aTxXT zrz9@w(nN~Ki3vzz@E@RpvI@!p7bY_6s{6j`8~l*kY2$v|eD1Z9!Rhmt5G%1lFNGGP znd#6A^^yhV5aYsqzGzV^BSaji( z(w^z$pvM#2GaB_|yA>DIFdXxvg&RxGubDc9(sKRwe(2yD!wGilS2#`URLTvD3C@Yw z5G@Vr(+H2#J#@7A$AFhGe%V7w^R1ocj+Cf_Pil+|z1o~_DZcY_;N1`)@CNQrs#+Bf zjyTPxx(XjFp8Jmgp?IROcXn^fREALjt*XcZ8woF!1} zn?h$*8e^NcC(bUMl*;kRpM~#=i?QaKDm~bQ zmL{3`rz`vmt<;FurbdApZ!&bIT&}0V1W9#<6Cpa(Ukh|?vAGy>;YK5fR>Pf{M4ozpFP53e7}X5FWaITUDk2dV^7RVS9-?(zNwrQFkt$0 z01Q{}EAFnL{QP<8sXtNUJ5NF=C@)v}$x86NLt})IHSKPZps6q_s($HMY;rbzp_%_Q z=NElQ=jp*+iW-ybj|==THTC*=Dz5wTlw$3Y?ladtJGbu|ZyM#Hm3P z#be~p8G9Boy@P>lv&#=Nop*d}Tnc?0&gGhdcHW4Ebq3xq=H!6{lFGF;(c0dvms)SB z4it}5J0q|w!ESo@hTnDcXbDtSdINq8ex;L)mPr$D4NC+krg;T)-AIp6zAx4R5I%y$a zy4Qic+Ac@bWmU`YMv(9T-MGQ~Dm#7hU^ky*(gO}~mq9la@6W4)op{xK(dohbH6u!o zeX50Xc;GdqH?BIJ0#>4hwYof8H>frIlPy5Xh&Ha_-ozv2x9#`hv3m(morpqH+q;5W z*8NEH2a7n}j`I5t6&Jz`Z)~~#XudH7JSQ-rl1`pzXMkBArb3NWeN^1RDEf39%eM%0z;#N-4szloqF$%I;&Q41Qyo z4EDu_t+1Tu;ONiz)V(Q(BtXk)3Y`tIOZKvI(AW%5yMk_XlE&pzXIW9te&-P{Ypjj~ zs{lMcZ+0%bSmSctReZ4AEkdj#cTR9+9#+bumRHzv;%3i#_Swj_v|&f8I%$>^l$nuZYaWw! z#3$N&^5zxiUdXu(#bny(`Sdd>PkudmIL$zQ)Vw(z+p&Hex6zSJ-0v!uJxvqmo_k^? z&28S3{xo?0k?0BAoZo!`vkZ?|A`9SN7nWmK)>Z$pejst&itLVf|7L7Ah`#o|>q`(8 z@a~UxpuL-oXrYJJ=am5E7S*h63)?98rV^HPm4-^x@GQkrHuaFzTP@}tR>%2>RJ>HF z5i)6ek|8rD^ZT*fMt%(%i7 zao?&|k(f{}&oU-${PVm_&9&(KD#l_kEC?tT0|xEqU75mK{|~ppD>!thTLAZk4=Aeved-5r z7wFk7riuW9!5=)w5uw%!vT&<5@v;53&f>+tgu`HBXcSyNMvJU%+A$N%IA5WrSvF81 z&d@vtMaHSxy-s7J#v)v-&H8UHfGXb2HW=nlmY$%BW!JojyG@2q#=>y}!#k|?4u1lOO{XJu^sr80i1S1LK_3M@Sx!Z7LayEGztOOubporJAZ$JAqLFL1+lY( zfyB{d3BYKqxbWS!%yiFPm#)W?8m)GZvK!w60_~y<0dY2i&uqCGyxmU^f;h9|Ksdn% z9KXNdMhURERWSc|(2zkWhvCZ2rxNyT9;Q@+meECTqPcBZb<3e^)BD{p{7AXB0&L)B z?&nNwb;Iwer%xWKM=%>Q>R`CagCzJL>i}>2zrmz{|8aSGZd!EsMgmZOj!iKqHB@i_ zpuD3ncR~PQy0K`UvqTDXxW-z7|YyjI5y1 zB_)&gy@{PxOO0}Z%Pt+bwxFmjTI+7<%NjibACm$2L@iN(p*ik6l?X-uS)7}>6ow7lX{zW8Sf zN=n8ZoO)|OD1apZ3$KK1g~FlyGqQ;m0k)Iieig9Drhwn>AdUZ{oKWED)r84$1z>tr z5m4cWBGP3fu*e||{`Lcj{+9wV1P>(v04JdK9Qfi1R44zNqYRn^uYq>a4338fr2k*m z2Al?WaKm5ZV4x7tkcKyHY)}EFurUFp5wL>i1Yvj~t%_*vekgMtAHOY``}VswA|u(sXq6X7h`T4Mx`zwDbm4nVFeMiK#p2x5CiOBuq6#uBLnRkyGFQYRZ@aYy++A{mkFq5&# zUmyGrwa!HV`G1_&CgO6Av5CeTTyoK`Y@BR6bUJHt;?YAJKgJOF$9Oo&whJI%ex)Yl zp2TQ|B7A9Qu$dg92KG0y74iOj%h-ceK;Xhc{9?XcJ9)rGm{B!fOlwU;2dscfq>=V`zSm%C_ ziB{igAGixC?lG-@INbR)&;Z234B%~pe$<>`gYSsMAS*3d3m5J?v{#FJJGmk{A9{Qd zk?+PGy}!V+tPF;c8G-HZK!rqJ6c>9UeS$jgp=!W8AzZh9lUs+}Rj3A4ASr-n3x zAy%$#Sb#{RWMq=AqRg&lOyb9gefDKRy^zsO!}`eAIc;kU>Fhp6oA3X*S%!ZAPApXN z_&>>AfCF^Zrq#YT0n@_R=$6vf_=A_Q;t>n^i^i1IZM1p!*O>a$?y3wRF_hH+Y;n%+ zLkl5r5>gb9m3>R|8?<)vjBFf<+_)npB~)frwJKgVioX)bQ@#Qu2cCD>fuUHVBBS5Jcjekd}yMYscivdQ8y7yxKBP?&8%d$}%)5*V8f(p^w0 zoQb%*%DllfVVj#}ctOTJm`sNu4-hg2*>1Lr=004dn=a+*P}0)!1hSM+U}YwBv@m(z zKVu`ryUfc&aR_vRvEd9nz*!K8)hB+`I3;7RaMz$Tyz+M@+X*9hYh9f# zW%(WVbU*@Jrd)!7){63Jf1%+l#83tG2`JvnRNXo20DBM*aplD=TlLY~+pJ72T>F=GY|lTJqu}g1 z&`QP)Y*p}8LW+{1ZNKW?$@khm zZP^^ne_j7TSuY1N$hNUg$84TtW9Mz5XvvKIi|CNz153>AzbrJG$uLKu((R*vf%*Vx zrCa^atR_nWLuwvL-Ym2H0*UjwU5dj(4rqD_h(J#uX=P=uVgT1v;4ytnZK$4onJ+i4 z_v1wZir>d7^u>n5ijUXOGvQ;EZpl9WL0fhJ%7cW=RLVTBoyM!kX&;#@5aMpvO>t8j z?OQ_RiONzY8NipwDNtQV*A;)awWSASmS6~0H2m!UC>oAlUxgmh&7Jga@uT=Aj-YLy zra>uz3J>4+^YBR{0fXj~?AAKuN zMGifXu6|tK4F8~#Z!O>a+^^9?0e99pok!5tr*pg5KH=QntRo@14Ws|Q@^5t^wDkqt z&BsIkpOUMu5ENr&B~BpOUfOLl+d70wz*1vEi`u+!tQbtp8EyxTjXP9;=G&(*!2i{J zB4}QnRo9F}1q78xy-HoVBS-RBwi(?@HD-xJ;Vf~o0HH#JwWq$9nw6npMjZ^hCBaYr z%q^eB%R9_}5#hbg{O$r@kOA6c44&_pq5dCj3KYl1dyAiTFoA3wFGq&C3-IY!C-!tS zI)b%45SWERFFP;=6U7AfA+Rql%K9tj5yh))8_A6LBca|&JDk$i8*+ntfsTz(2G3t= z$3^4$$%^;)xjM^)e0p>$8M?iD^gnk#Le&eNfCpXzgzA8z#G{G&KTHG+9esv>0(9H+ z-IXaXxX0^bSvWXIO}caDTwkS5CjMeM)4+IA%FU1y@Jpas2ClrvHT7_mDxoTc>dsqg zbiwJ$h>4M1`XM@i7O_M=>kb4+ekY|BwO7p^=o7gzK~Jr@Q_A zdrFtjRpIxe1oD6TY+xQZR5JQMJ{!=Ewyhy8WPO%N_!wl%i=CSf?|ZNRn(}{vGU1^$ zwgw^_+06SvC2s@WaJzoy{LY~UAF(dXYwMqD|MX5&qU__5H^1A{6&FW~&A}WMx?qk9 zG=MP$Y##~#Z6AR1KcNDwb2UT*aJ0XGQc?5KZj=bD1;PO918b)%g8nzoZEWBUE(+bkH`Z^!WM*DU`KO6RIk5TP2dMBb`VhR8@n9?!)SH` z^uT-r7a-8abpU$$cXi+i|G$6_xc{V|nxDXrWC2^W#ncxDxagRH6@ImndIOt-2PY{* zCySK--nu>TZswin|5_b*;uQ^CnWF%2{4XYtx}V@jxFCToQgs2@imU-R@;Qj!0h>dE zZvbz-TK3;tUjyFln;ZGRRtKJVCIuJ3?|?V{R{;z#m;jI1LjhZq2NRN{f#HP3n_(wl z2ql^+cA*7@acc}zfK=`WF7k7@@4P^R*>yQ{)gOd6uk9T zrhjkU1?W1kuEzdrbzu7!;o!>J4S3^!^|1i^2A>|nzvZj>2&|CiN6-KVw#9_MTi5&d z)(-%mW86aU@6~~d8x{EHM5n+T|C@UxnyGHNKYDMEVr)__neZhu8|y7TXu^`aaJm#{ zG7R8xnQa7UhB739zq^i@DEvDhWv^`rkV;9DY5gj%F-ZEHL}s!={1y*+Vlc!_3CD@d zqdwxH3O_Ia;rVv+HFoW3>rGN>I=!^?7^ufRakLEy83jm=6HE{Hq=Y{v+K0c6Xq;F$ zQ3c^f?@np|U0(o9vl5Q}-}={Q3~)6mCl}Ljsi?$Osaq?sNZM8125^VN>o5(l!-lmoMgMeL!5LT(LwZ`fiR zLse(CxuQZA$+@P+h5Xtao1;Y1?s?k+>L6SYXI3tc@2mwMd&x@(r1Y$xu$zA1GS9n` zP;||o0F$Dn9j;ePHC?Lf1fnSgJChww!%Vb5v8Pr;6$!BEkv$LJ(&I`^A)o)*0ens0 zq2Lqkk9w0%(_ig10}X5d%74+te75iFvuX|=F>!h$b=<_**KkTUqBLx^g(QsxX1mGB zImh;?P$v7%VNEGIm@)%cUi6*zm(*t*S>m1@o{J+&yUp^)Q{% zP$EWXHXNdKqw28L_v~c8kB!RG+4PYgPb#=^svf7F}^_Z3v zTYJ2x$axXPAd2_7*nI{Azjf0AqelfS;%~hk*anJ0x&iQHAYkZ<26LsKmZmmA{t0#1 zm)}p{P&4@&xKot&UKa-j6p~YFw7*b0m3~Neb9UDa#(Bx9p0X^e)c~fKZkj(z&n1My za5P+9QFi7_$y6>L=|NB?6~av|vSuE$qen*M^yOqnSmu+f1i#CS)|7I((`S&lC{&`? zv(?gPAfN~7xkjf?v0Il~>wfSdBS^!wBKa~H$~?t+Kl-DD>D1#_=H+Jixy89ywgGTW z@DG_%57<{nn;Vh?>7j(7$k&;i+w>yQ_*GCEV>%oE>(mr;jOWNRf6g4{lPfjKgpy)< zibicZFwbXi)@?UA=XIH_pFo!iP=r~NklVa+?og%K2BIIEXpRirvf})l+Rs|vi+}zp z0${74Hjn0fezf)stS@*M)rcN_cx>(%O40WiPv}0TGffQ}v{`xF`(%=SgA#hMPnLm; z)DL2QcR&iBK-Ro4erjPnBe%kLrlDa>E{sBS@A+0^VA-8Vpta`OeLudh?YUiUFd<}+ zchY{X@WXwJ2)7RJEm7KGu8;DR6^+U9lwQMqA7r_1v&=LCQfbPi&rW98C7vMg<9lb)>-ezzgqnlt-5 z`nRQUDim_5&vx#*b~Be+uArMf6MIW%pOltS?pm+OmlW*1qf4>YF3%PPuS43lh78y$ z0)TN3d~Xr{{$IXUXbtA*cF$J_@SrAwClCB zEX^P3*;1}k!k}A_9Lm;GOP4sADn3`cz@*Q;o{w-J%0DK3G4SLN)()O_1fn0qq?<`4 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 TVtppV0{j^28SB2&c6j_x{h|bX 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 7d284aa0d83b39d9e18a87513e253d2beed93a67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65865 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%0Ac{FnqtfOh!2fOigb1El;ZUwcrQxXzP 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

}^PH`@eer&uWUVJWCTw@Nq zjglY|9ypibu{$V^b}Un|01lp7r5~5?a=K}#K43tO1;!G#`E=}Zwpw5tz?o{Z)~Y=( z8ML5~3eFy?4tMU~|3sUN2X}{B1LHXM@|kb5?2whV8U_s3K%w>?e4y?Oy`GwaqF)39 z3U)T)Pk3tz%2#*J2g(ri!g5SYL#0WITkRpm(qi#BrBO1&O!Tb?AX7;Yzv?E=AReJYpOdN z7luTT_O>gkrKQ+uL~NHMIHVYT2BYQYif?LUuyI*lkluV^a}rD(an6@@_BZww`mfqmUS7XY zw)zP7@xPYHJCU@VYsBq(Q5PKRi_Ve#`iHK_i>4pkB@xF$h6#=l5Vak7xl=3q2Q0wWW?$bui~dIYQ=G3iXKuCUGh8`yFxft zRhtJt$qclW0EAeZEq+kJN&EOD`B+-j-7-8A@%SG!ZpsdHn%$UqeX#N>s+tIJO4UZUiN|LVsG%I z^UxJagSm>)3Gh~fPv}hG&VQTR$2BNaX{4Y^WSvU#(=LOC5bkUp`_jBn+G;i7DvvWY z``Lbe5~#<^44XZ9hVWWhKwfQ5!kki071}JBH|8c4l&fahE4{>}Su=-#WlLc2`^2=4 z#2kUK00w68IgEx;i5CvxB^ALQ_B2xtQ)$(!mNbsG?C;Ll!qO+caWUC;%N|#PO@!Q6 zS+Kr?IlY3raSZG#WH8Zvt-&ZnkZSSJLWAN8SrB`Ul*YV4tp`8xrIGK(w@bVTRiox& zl&%3QooG1JlAaO_&#Dc+7MC}}y7~+#~AQ|RSA|Rpd-aY0jKP~KgDrAQr zi|lphQ+^pK{sr~4w(sa$JlS;=o^%Cgu)cZ}q5)y(#z&)Wl4&MqGYdgtwRo{{G&xJ} zgKU-v5BmD@GXhQ+Rxy-b3<<3Sk>h=GZU4qQ-uW_$@3XVI2(}5JWMgctoPuPtV&p9V zuJ50R9c+gEsH3N4getxJT^Tc#-a{@t;QjtJHm!%7gAcJQ#(d~(*0 zlOCm;k=$^X4TN)#CEqPAD_hW2>3wsZC$Tq5?$nI*>U#9L@q3#c%U?$lhxL2tNi&z|J*-4YEiJ8{ zbaNn0E8?D?#6^zLy?MvRC6eQFSW9a7R^(td$>b9gwf+uM1N^N~uue3%mH z)xGt0a#N5{Jp4NaR4gXq~d3b+OS-n}EK{GB;bkc-4U*JxWf?=&P2A zHS_I(V2%H`xtX+{eVEDN!DMqubuKCH@kQKK9I4bd;+qJWyQi^xx?aqi_uwnS9Es(o z%G0$r&ATn&XO;iPcd(6&oNE+HC$?kfxvItNoB+NRt zFlYuzytEeVu6YiZ_9gA&2c6D-U;G#Qn4(FxiL zO(`_k&h!`Fh>mf&8#bwFDY3E^ecZ5vGhsb*d%u#1yE9-D=&5Nc<0DT`huW+No}+e& zxP8;hqs8u?*`f~zze(gMHhN+Oi9esR)Z~F4Yu<;f27*KC^a-%{g(e@LMxe*2ivr*9 zkB?@q6b;=A_v|M8nh7e?(=w*GHC^-=Iv~X3C!8X4e=|?yanSXe_uJnEBmM9o7<42E zbom0|T}&x@XdF~%ns)Jm?JFC3^4bLQNZW1vF$N0wGUzB!G1$s;Vdx%x#;tyBFSe78 zP^cr|{mF4~TVdo{f;4^4NG>%sj=~sSnI+tPSURMk_G0K!NPecZx?2b|!`=Wb`$?H( z82-{0@t@EUG5)LK9fUxd{AZs#(*u@hAN=@fsGiMG&w83Q;{LJIx6VU_adA%O~0wm_z z$%c-iAXl^NvK{Ym^l$Lueg5MI>C4RRu;j2SOju~kLrR`(LP~_AqaX2ENes&=D5~n} zBT3`wCaX!~N~)UFshX)N1}Hu9Qu4NyYZh(fNa~f+qnRAI#KhV9Kh=QdE)-UQpZ^Nf zuo-qLxRf#pOHv=nbkwRjaqlxT3;>=DepIv=Mk1CxAbsLvk=~4HQ5RXA zc>!vA=oR6#q5cP0k)n9=>)yRa0RG6zIQW+X%`|fJTmR8g>xBmlo zt%ec*7r?5z{>^L2Gl?3|1o4OT5-;I=gxgHo4llTj&sj*7v;^z=39?w=yb@sqMqyr5 zCCTw$fbrMO-}%TZa;K=~r4%^DQNAkwt<@>qe??rz0yE`*4&Ez*eQ}>k8#puWOWW{fX=E@8y12*{TaR+?vYx@iJFmzjr4czn2p!8<1l% zDYV8PYp()_5DV)@qtU-41kp{I_ZXHh(EO@mN7W#>|JBlezPDA`x z9${>9IP?<4f8!ME)&;8h1NH>Gg%BFB1boH{{}s3I@p18C<9H*|GIPmiMN#!iih2}< zT$4QqQb%hbB-{46}j93(Ol`eky;2K-b8IWGKsrmf$U4Z<)Lgu;2u ziP)v!sFwc(GwIw3CE}(Lbi?^Qxp6g@1HUPbs#?YbXhfnNdj(u@LyI5$vg_W$+@sXbwMx%A#k z=WB|T_*Pbh1qB)oj*fF__X}sMOKzt;I$!Ea(;>lEsjVXoy8%-?_zlF1rz6wC@BZ_p zU5GhiY%=Lc%KI4@=fk99BY6s)m9#fjFrq|^QFD;sG++R>j*vOp(QF6YfyL)`gU$r|z zV*tE`FJL%nbUgh+XL;mx@IVm$aE$n3U^Q;`NOJ>LH5t^Vg@sC;wQ??ti!vZky@~Nn zHR5A4$mU04?IGh()Ij>o;v#Y=FRAiU|55;Onq%JqV|1JymQDqy{S9VFA#&PX7=-ro zl!U*@;3q`%8W=6S+H4hR5^ZLY5c@A|Kb2&;;*mCuB|J;8X^kAI&v;18l%!oFXbh90 ziu=DGQ5&x?M}FX12kwK>y?5*?HU3C~sG8<6T8+5xH7eEpFnswbz=~w*sjQWcaB_3}UQANdr)=U;k zg|W|GCkDl*S{42Uq16#w6>N@V5@P8`n-CJjyajG~q##`icD^30cDOJ-4*c0_qpJH&Q?Zb5zu%Byys${dg2cm{>sCDR8b8A4UNJ%-^c! zF9s0zlcs2Z82Vu`l6l||8X_BRMeo};SmrD z>k7n<8$fZoysic})eg8JFF()EZJOv-!!`n*;e`Y&m@dI-@2)V1xd3TJejvUDA`qgYbN&e!M_2lFl>8BL* z$FGnIRSJPlV_5jhj}D!HFIMK<{52HVNL_zQdAaOO*#tS(b%}I}3r|C+tGwWK_+6!f zp@SdA^*SV!n+lJPq>i{;bp~KO6E;SXFzdA!qmH316W+aRK8lnN|G>)an(E3~>sX;O z{*oV2Y|sfmS~hWFA; z&pnUV(*5nN(T}2bFAdR{4I5LqkJp7H)507r@XOEn98a^NVsN}g_38IZ6|2B`Otonp z*mUuIx~W%3=R&q;afzv0P-|a3eqFB^#h{4t0_4)4t-1Z?8wKte#cbkVcZVMAH+6`W zCe9TC*_=0jM;~u5xn}_zELHVSM_MfCY}7A0D{Ot2OCiAhRS_IxVpJ@66f+0ZVdVeS zVgHjGo2h}%@{)lXwF@ds&26yDu9VR8MOo%tw4u`~%ddEK{|~zUGAs)2`vQiCmJ&p| zEqW;F7Nk3d?(XhxL>i@Ax(8(FMyZkR2I)b%`x$Qi{onV)^L*mE=3?N)j6@>(9)(# z)7v}K_WDkcZQM=r#$GRZU~H{m&nTB`7f%Q2KM(^?I-QI7#8f%)*|E%4ZF3wAnA4u6 zH4pZ?4($y2f?KDqoC4N}3wL({bKlGLVIKA=^Xa5lbwi2jR~2opr62O_BrQ^I>h!QL zP5d}e5=-IEVOrKAvv=W0uyoluNrldn6c&Dxx~giCyxvq)BZoV)j+I(w#xa!SVOB~t zT;r8&^F^2-hXG(#wVnsa>xzshXG&oO(yc;yd0<_(j%NUZFyj-y=6e2oriF&5Bq^<& zTiv2DpRR3c%6e_cPR|VvO&X`rF<2KTf!QYPMs9@IAVFlWjw%@bMnD8rLpBUYudAcg z_{B!gpFn~ck|ASj-L@HL5sv6CrIjIBc21#sZwJ$?i`Kfjj|cp&O0d1%j(WKwu zjN-rot62(0)LLscL{QNwUhn!yLP)rAK!-PYkdpOdzngo-#W{P!JUA59D{+?fqsTMI#gp{2FB#Qa!$2HY zdB|Ru(7=$JLL@jwj^~W=dT}%;JE0`$NKr+r5%U;Dm4kN>z155FMEm?(xDkxQe+D(V z#PTQ7j1@{%BP!9AZ&A&g(6Z1M$kk5MXL zP3aQZukE*u`G@LK5nWUbt*y0R0gd)2e{3u=Yljqu^QD{RZr;@L{4oeQDf|U|VZO1s zDSaQy=XJIt<`|&_eEH?e_^2aj+2;|-s(r$`3Rh*zN=q_X6`m%brCdRlh?tYeBA_lt ze+PQcDVt!PJcfr;M^0-9>9>}~cl9oZxD1^)%CkXJfC7mMkeFlAD94rKW=z~|KH|*k z&noDppcIzYo6>~-Ht4M`KfE63yiqkIw#S)I*D2^I_qbp3b?p0M@@CxSz9RbE4H(4< z%-~dNvG1^VU;pQIr6mAb{ZPnqnY-XY9bb?h2u<6*-%)a+7W$mfn){#hrMQ<8JL)SMXvmJvbX4FmKru$vU`O3mJB45$N;~EXh;C zE7hg>3BVFe>XE{JB>H>93BMn$+Hcoj7fzIKesZ#9RyU<9VydNQOBm4umGZ5IUlUm6 zvHK@sRUbPhUEknX30X4Tgv@EvTpibJw^KgNFOVLriE?#PTwW>0cUTAYt}Dw*C!c9! z_pZwM(gLo~tAfMMrmywx|1yJI5HCaL^}L8djy(exyTI>lbC*_cH=_K*mM;Dnc<_{^ zkqB469MU{A!SCp=TO9>E!gx_&? zXZiF80*)_p3w=onOX=1}t|R!K$(ej2Uy=r>g|t!wy$u(D3Yt&@A4ti6mlimBw)KX8U!7l30k{-*#9_;N)z$I7ml%9R#>y#rB z5|S7|+~#f)#2ACA1CbHO8Yw>Vk@j5pNHI~#!;sQA&jm;6oVY2xFyD|%g(k6Ru8P^T zR_5z;{`4X9s-gys<%pj6(LgFv`tx8^L(msN(jDNuZjQ+}C44mM6XDoR=Ge<~P+A=Gp%* zxa4)xtr(g#DI0iH!`ZQs^}#8PuM=yLdHy2v@JnBETFSLGTQG3PM-BEVJLi|q`3o!R zKHl7*tzxVN>o$4oHLnr|wcEn~w+$%hIz$_X52-}j2oX#YUdGIeq4Z{3N)%fFJGX>? z8}hJz8ox1kgh7P^A+Q^{j6CP_Bnc~57AezoMcpxNDnVgT#LHo1z&_Cwa+b$cbdCL8 z5&al^lHRR``Omp9l>##;aLz8I(R8V!jo;5gC~5k_%^FW*gXaebG}kP0-75on{yh9M zR&@wsPly<}Y(Lo_EB2X96XvNlMy9EvqWm+o53U}p<4ds=Anfs~LJQw&ANu~0lq~)R z=vv4v!J@gD`M~b??Tx#iQ0HQZyoBUX^M(G6mcBK^Y8Nf{#QK)%S!HuqpVtqs`}L8* ztsb0&WIkV+X=zrN13e(0d8KR8ak1frkhM_tgbl?FslgLM7}JtVl-xq;z z6aylQ6^MwIzU=POr*&@`!9f`S0%WW&t$|m}!ZPLmVVnPKz6x<2P=^d@1Js+mc{6Kk zD??jf?&bK=pw5Grn3PKOQ87eQor7&Q?p9leny+ak8lvpu?cJ;fQtuy&pj5(KXkFB8 za%<5N;_Rm6c8T^$TlY@YmO0 z6>=UQ1u&0)VWp_IZi6=*O5=1TbIWs+&r7N`G`J_UxOs~)6Fy}(pMA9Y6LTU zT%yQg5B`w2;>K5%zOyL6Y{UCX93!yEXzC_7PVY|IsB$9H!ll5~$Zf1%1s#!<*h_HPsiANF^<>fva-FkNPB{PV-i(~hq~_j_&a zTShV}0O&?}c#HQ{IVH)+=Yl4I6vDRfncpFN>_;bEmsa(Mc8d0;Sms14C*zKG@8X$RSF`Ho$@w;ad&d^Rezk{UO0IhV>#qYBA6X_IpN7ho{=A0oh2~iSb|!n z7kPi}25INNhPyhx!^RT*?pr%jYKv|FLJJ4 z)|HU^b>$UG1<#Eq4MJIi?Ucz5`R4e0a?P-PYr{1Ry<ZPpsFK|*3=h~>LGh8p`+o2;zFG&ds#yXq!FzmGM2J-e4cCU?d+qSVapnBT5PXm z_fIDKC(7lC$@`^)aF^Dz(rk54*2~-X_M!dQfo%KrmoDAVqhuGnt>eNq8I*n6EpmUM z-*I2M?o88N2paWTpafCP!8V&WFiv)*y(Dn{UkV4FDL>a9(P)SLM(C0LU=-zQ(BLi@W0{nyAZE&mb@dQI}m`Umdjr zf@Zq1te2RRLhCUw49^kc z(g}a~Wy@j?cEWm-uv7ZnG=&EEmZCTxgxp!?Tx*H%VwWFwCTe#_k$6)y6e^$4a#dYyk^ax8^pt7gzG(U(b*s9kZ#I=^@cIf4O}hWJJ8n}|lI{Ly zL=_Gw>CBl4asFp*ZtsGF=H1R4_s!-1&QLC>i5@;{dp@nw4F)AmCF%uu{f~5{*J9$6 z#azz+Kk}t8eJ4!mID7B?)mW!TY4Nvr@E+8@I7p=L4E=U> z-&kQ^Jqa^ZX#AVGiV8FK1slF<;7f6zCy|`gLYr>VZGM3@%~z z0kc7%Qhu~QXWMlgX5_e2THp8>C#3|ya_?|KcS zj88-`AaBbokpr2jnVVf5RZ`)Qk_{1_zz)n0Od-Qn6wB=UXeFcwJs|}WUF2g(VFto{ ztMJlM{WXw;E0$So)HeiRDM=4n=(}zXm-&zF;-|x*awa--B3}*V3^{|h$ZwmGA4c$sR3{kC9 zw3W+8{tX`pC(qo0LQ|uHBqi99M#}#ya91heMO#}0Pcj@qj?SO%h~acLUx3xr)uc2$ z8Z!C(P;AEC@voqyg3mwEVDe}m9$~cxCaYXeo4Rj}Ts!bT} zmpg5tT&H=<>4v+pdpZu}zm}sk`K`^sEH7)LWzQD&xKmCb;z~|t5M$D?85!v$*zEGd z&4g(Se%YsH%pR&%jaieo1Mmtseek1M6E?^wGTY?hlO^E(r)1J@i9xJK%o)83SKsFzs51TR;}Gh{ z!Ug1e({-uFG7(PM)NKIc@AU211dgxyD0`@Ngh?&R(~3`e`6~r62#^XVPQY*Z}Nb*f#AC&CsR%rgcw?>+k6OA^@@%`^8yqJjZl3D zD4m|3!Wlo!&z~_kb8uZeJvDW{B~@sTmKFYK`^{05C75%RD5R1_24LEkBty=BUe|qt zPgt^SJe5L%7PvVc;ILG7OdVt9y3XJrcv~Zhral+vL8BVGQ~Zz*4WrA72F$f)bW zKVW=#mbd`_IWRS2{f`*Xxhux8OD84EF4IWK*Bn5872|OXLd*vh zDt^s3nr7Ml<5Lho5U^5xcP7c{(I`Vm!Jzu=5jH5XzPsp&nPI@TgoZd&Q&Us&jv@I( zQQ;$Z-tX}TY35s6$Da{S=hdV#9^1@%+@rw(8aMuho7R&llSl@}qDAR8;}rz}khff%L(uF^XlI^b<4*BhGR-+Y!(gMO#~2gUf;~1@O|P zYY(y)(C47U}g?usN+xUFnT&-?uY8gF%;wnm*tTe$08AKkL(*CSOUO8_Uuk*T(l#3_;p z-*-8HoYwRQ4N3&t^F<0j{qSj`A)J&*-6-~D<0Qk05QSj*-r_Vu5yc$Ee(88p)Es5H z!M(-4t{Fi0>zL$7JH^j z*280@qFpOrvCFuq^W-V2c%9cz|4YZ}#c+ex*mlWqsm7ih)?#3^{F~yy!*I?k;|eoZ z_QVLg40?_(j;>`QwD#`y{i!EqMzs#AKpzQSNs_9!@-7sEM<4eaG*^ViPcP7myfz! z@lp~|{YMsvfvc{23l#dzKA*8yZ2M>c#?{>YBE#59p9k9vT~7;bjiC!>jlQr~KQM-N zn9|%_Iq%T?!SnDQ2VleR#G)$u{F6o$^YqB13cMF@=NgRIWrdLk>_y_4pLi;yVPgBt|F-{Ix>y_+10_B| z2cawVIaNvKP;HPz^=w*}prh9sdV7_B4W$0FcmH-S#S6PApZVPcnuwj(qQP)GKO4 zl30_~%Uwxu13_R=u8vv7j|vRu9?7ld=+*w$>A1kC6J%cu8KbbW_^*bXh%#Ab)=akV zJkNJuVrZuw!dBT}sMMWJFB-|oyqpM-?1)(lI^rZcg@NYM1?_4V~r0u z?vQ_0cB5>_oSWRPg)TaU0!Y4kSzwM=hZ_GCddoSI<8s}R>?Hf>m(8e1Rh}l=+3Sri zeVwPMK@<_7QMBvDL-}<=z(a4=455qRLmBh_jL9THpln>WV#%YL!F2I@2{S_Kfp3NP zW7!1kTj#ZQjGGqjUKKU$8(`O{0X3*R`24g|dzpXplA4=Equzdw2}jT|XYz2C83`%G z`FaqzF>U&j)%GaJ=iTdd;t zmbNN}suq{f%6&{j$LYXBGPB)1FERhLx(4*&-e-!S8~<*Si?gA>36p4(;ch0jb9_3O zo>dj0S(cuTDSB9phqg=iwGLtLQe9f>fzNc33*qim2Y9Q)&4((T|t0y z%1OFyAcm%HGGRgga&iskG*ip2f%el_@1gNSt#-BaR)64)XJO8aYp14% zsem9No#iV&PR?B}@N0ZfKPkCaY)480hltXRBFM9B6QBvf8rMQQRWkpKo3xvt=vd|T z{uEu!1gdbmhsXnMsRg$ata{Y9w#r=`&H>R@pXcR*MfmtzHpVv@ov&e>G1U%Xe-26k z1|RK$QQYqjmTH|&X*h`o`ZC|bFC>#+Yz;m39T*<&#w-g9ng7Y4AnW(=5Sx&&B?iHna<9Ra;A8>o?~# zpPITMC#A_TZaOLsL}BT4R>x)@Ene}AF0Tm+!{X7#;uEPmo>oZt-O`Gckq zmim&Hk|IEzQy4!^H-z+?6Pgja+3wQhwNTdD;pD9#cI>V^_Un5=YooGNd{$RJ<1kW8 z*(q;=&Q7hG*EsQkfUcaE-FzZ@u?eogZ2+(fv8zI>yy!r~2Y41ey5HH}R_k%eTv}S1 zTr;NJH0g+vQ$D`vEZNaw9@0pdeRg;7ijiNZtgM`sXzq>A zeaAC?ua>lVC{-=(#=~zECn2Sf_0E`nA}!#Mq7#weQ>Q8?8_F=2=v#{I?>{K$+%^S? zr#Q@NpV#5Vho9;SAge$Qlt^xjrWmf@^OeQ|rlk@is+j()Gph!m3NN}mV5M@l&D%q7T0~GzFi#5Y`<{Dk9QSQF{gNGoLYFXWQKnPibMz3} zeuX`>?_A!7re5FUnP9$hsOF)VnPbuuXBB8nW0cKJE47!hL` z(%(L-uvziF6>Rd}4?jD<+>43?Ig(BP6sHpruHzuTK9kK!iHH^KUO9^@0iLt8&5yq# zvR@jT3NY8oxEXzjs-cLYi03qxJHo1`J`K=X-?| z?N>wRe2f-;dk>QmC{-MqEgLQ>E7(@akdnlBt1vzE3) z*|Bh4m<@#GPQnaszX@Dye2J>G zp3+rBO2ll?E+lKW`P*uEvenWj*~DAnSBJTeiVr^@3;c7~+1bA=8e6L=G8VnM3cdL$ zi9L?;2w4=Le^SrDIR|kB2oDM!$Q0w5sHP0@x9v}TA{s?DBp#+smhInlV_<|L>g2(i z9E?(3o9Love8Hp7-lDLAL>b!%kQV!%DP_Xn0dVKD+tb0IRd><^qC6wKRz=!RN6 zY*s%O37p=YCK@Qkw}z`!Y$-R^@XmOmmERxCT6f_4a7|PEGh@#uag1 zhAQszu8~jIiz|?CQ8=4AbVMsfb}F+!QueI4f)NpfgbBitCivR?%aSB>1i9QhR^p(H zfU&>i!9}vZGM5ujVs5mJn{F!Z+ zKM;1-WT;6&)O*FT-1^P}VC%3-{6N7v<6Wr>V-WE`%L!(zw_Dgd;(o@0J0rci(&TQ- zB++0yvx?F6cc1rZ8-em@Q z>-}~q;%i*f*W^{g_*IHKwJAO!x{V<&HiH~LnKUJ1Vnn~^5_4>UTw+X%JboUYobxutDqF5V88PS?w#-N&7{* zm7DvOFFlu3UCSg*HfzaSZa9l)R}wZUnXTSBsFJol>t2x-VgIVtWDvZPlm6;sqnG9T z5XAz;%(<7t(~-U}tL`jIhQ{!%A^x{I6$U8y$>G!`wW^mPz8rx?0!P2PRETiKzozi* zl!<$SAE%=nqK;jkKNAww}QlRrFN(i%)E7lx8~PGuy^qYossC{NA4v{9kqP0&c`K zyC2NW%?HKeD3exhmJX%d_HQU~m6yB5*sfOxflQpRI&6l-Gr#ZF@xPEuAOI%^?;BnTU zVNpG>F*%7hV?Xt8rm2XsPl%*&jIAp9PF{O#YjP&vGb2EiKu+yA z#gzjuF9IbD($%qCGaQ99*h5pa)Xgtv1YGRSvX$A-h4`u64mPB|3$HTh(~}9WoX@x0 z$v;%GNP5CTOo}P}dkYf1UL$)YSTwv2?>b;geqKSJ^OgLjI~jWxHjdmd;{}K zS`t0K$A04DgTccH?6X~xE5FrJ0cd~EqT2Ag$pR~j)oY!f|G-leyuRH3wvloF8z};( zbRonL5UAZY{(zS#jm7PcqaTB`x@hKFA6n z{lWt`snFLSpn|S^Ed5LiVl-{vg|DgoM6p$7t1rOR12bamR_Z~qf;V8>ipqq{Kjgdn zd#W9f;+i?lfX6`XnG+94*d!*~#4*ubk%eO>ws=>b%4M6b!OR zl2L*MS{c@m*66yamm-6a%Z*Y=k<7Ly1$3lv5m#Xq27*$XFIYLjeCJAT>0nTv4Sw0M zTog*h4{+B<|LN#_l8c*P0C zY1agY{x&$%wwNQG>PAr0#lv_$8jhz~+P!G0ea5FZNL3?>P0jGa3b`!2QY%gPG?TDm zqM(e=OWBq5K2Kgkk#lSOwK9>k8qK^x6kPLO4)>NxKd$NTNveSX&{_nW-RD6WF%+SX z+V%pyLq9EzeBcG>6G;QVSj^NKBS4I);45Mh2y{~Yc()=YtwrDac9(vtA!+9qzCMR5 z&U5HWhYyYCi#EJAFxUU}OXlFQjlYE}YVdkIB|xwJW})NVE*G^51$z9jVcOVj3Mo-x zxt=Ws(?%sUQMOypxnQWh5! z&kbv3?Q{micXDo_lUZ*jLT03zo;hL%TFRwalIqO7*DrA*UlPt?dy^AZ=Ozdfzv#i& zjCgX#2%IH*uVIW)4?BPVY&9dQ@JbzS=tG-N0rHVMoYQS?_TF$;ea}VN@@fcJ$sS2` zMyMhdWUcw(G3W7ESjt->oUE@vqCvfahmQ zvH{KDcHaT`Ega%O&yCOTU*ojDl)9vhhflqD7C1p6DDv)|xJ>-vvr^$WsMv_{-ti{q zo05nn54(@CwmM&y65Lo7UlPP7TJXiooJdoarM^!j9E#ft8$Tn(Q4D#5`MS|tS4+?$ ziy2Swrk1(q9L20|gvsVfeEoliH7ehuJhP1g8{3-LL2Tz*rR(jMUKh?f+WOk+&hznY zz&Rfd&ITz})u`y`SlCL58;!EelD)iL<=sz%hvKiW2^kM_OIx{z4ucny=_pq+!k9My z`ZCn|a2tl}tfk?m?Md>Vu6kMpe%pQgM31~#X5*M+wn=tq{&QfnK(IuSGC>N_u!Zia z=h=DK;7@&`y1ufyx{%V(A9@_$<5}=(gaf!b3k8s0{-RcVshb`=f7GPj<*Z#AQXE=w z_wgh+J;asfNgWY13FiXsU;>zX12Cn)z+|vHv?xYJM-^zMtB(@^^U&5YGFo_DxxYUS z=d|wq?%9RdYWVD}W6sA#?Cy{_mB^|i3;(gV1+nl#?aLVx9Nl5sJW1b^6eEL`PksS1 zP{H_Zn7MSfyLndMIC8cPt?_HU8%Y%`7(>g}IH)eY1Q_0JDoXO^OS+p=T78yQM(1u& zsUj6oK`9ZUM6D76ZuQGjxVn+ny!=la2WK(i3Kc=+mYhwMK*D;RdfP+_w}k@K&iaB9 zsgo1u!pb%=QitW_qGZBG$(>#rQzXYE)^99qDdi4(Z4~eoUI9EUv*zc&wj~0C^A=pv zBi(R$IQYMF6KXQgzBPLbxMEw&$5VyX(1qOX^s2vKV;J830@`~P+bpdf>`b@b$*=$l z9+ZNY)LX+QFZHwmy64Ekof6loam&V>%`XTinyx`~R8AeXF}tBPRlZ6J&z@Kx&jXXd z1R_aZcPxnddVJN=HJB&-rhHOtt6pUTb35J5RqBI;Xv5aq_fJ%Y*K z#i;KZ=7SX@$+c9(-gbXaeVO7Q{9m}#M1U_&Rp8F_Mmi{PJvBPo6)?{XkJ$9+cj zK6bzPcy?o>0CB!(i~orlY;wc4PPcO3?ATHU{rZaA{Y#v zPAcZ+MH^dN&-~_`Cu*L=WA+P#6j9Ngz-~Z=Ek7Us6tH{0$oxkO2MdaW#gy9s+&AC6 z|NrvMmdsprpeh2_8(e}fp+B51-Ye^KWNj6HR?~`DR>#k+9i~${-+kDDt&Xs2f&|KP zT_u`}P?R`6_33W+TO!9ddz*KIbVmZ(D{L}_^Q}-dK{#-B`-yImgD>>3+K*xRph6He z1!FY)EX&i87KTBn>1k2S4Ly*)>u9qIQAc!Pxm_p>vOgOgJ?idgN%#AUzm-qjg$;bf zkJ0~cmJ&76ahG`4I}@OK0^S4WtvN@)bz8QJtPDuRJLcOPQV2}M@N#(+JAyQ&McCHC zK6mzx=PrrQUX~*5n zwaq|Dch!%#k2ENwd=%*}wyldszP@s(x3`cv0ee<7&BNY#=+euX?4bFiu_f()ZL`!2 zczE3|nrM|3d|Z5g62{{HL589HZAYUfJ9xu}7xgXqGdB-cncFNvlJN7cjg8P703$MM zRat4$XPET>lqL1@p6MsbwgY4^lCfbCpd3^d@vWwh&eN?E)K!*zxh>Fa(`{B-ojip= zmq+WfziPp8Fkvp-3qKD<_f8+XYZ{O#@uAG2j{@S}HVx^?!K!;3*+}CkjS;@f{=x5O zE%yJ^g^b_e-c69OM9PWsmX=lr!HzTcH8&+A5SZK@j7ZPK6yMq^kd~gQBDJuz#JJSf zChE!0!}C_Gr-wayWc27$bWBXzlwI(likDW}-CWLn%~v&$?5p2etgBM8vWiO1R$nYR z*pYLWCuiwGknY*pxR_t2rkI+WOY>$sf%a+WQBn;e4Rh5e^~kmr7I(PGc{J8^rS!_f z-v3X}1h#$JzQjpIL4P^@s~_JJvr)HPU}-2j5>LTNl13zlRwVQQISltwx@Zk z68h&C7X9!@(&8T`yJ`OS_>1TP&)R z)6!#6l*?tJ-|g61 zSw-HBQQc8SOVk$NKLkY$GQK6k&76h|qUK0e4%gnC9IeNdyX`wy3(37xf_f8pLk-!Ntp0`9jVN&BpI*2`d=yv2FM*)%m< zeN2#scK~{?0`Oc2iY#OZw}42gWKQkuTx>PSE1k0pJeLEKx0(A`UBc(9{hGE2{QtU_ zxbV1qgNHlm|GTLe;{KdQw%n$`)&z+9#;X=#8+@;OlI+vWw^^CsL0uzq@L)n@s}3ZD>y{|zhk9wJlw^gR7gRvY_gAs{~KsStXJ*CV+rb5Ygx zN{!y%P~82b@L^s0!=Or?hGA;Bs2e?H1qrN&KsZ&Rri{$Y-g&NNl``XvPrMIhDWpZn z@HVtsK+mZ^vw;o`G&lR;FT*VhhIvij`gO~K^vFHWB-3=+h8=d1o9xDjA8HfHUQwIx zX2-{2I8=XITY((){f2V*5f$?p?maqQt`v;b3r`9!?-?l>v%fo{;kFfV7*K65Wq54{5TC8f2MZTGbvE|5R-nuWV{#(tOM z*u2=5t&_R+b*u*Mr=@*w_5*ZH0n>D$GgQW_9|K$Cm9$joaHbrRnqkgO%k!@svO209 zhKN*B^i2NCw9Zcu_`d@ML1By{s~sb@mAGOFVCmAX2=?we|N1@Re^+;TD>=l}LPmCSE1=l(r?gig3?7TGl=&1I@g zZZcuTrBT(qi*m(hQ(pBzwQKff={Yxq0#%>2@+W1!KkbFj-cn1Lzbc(MIR}C6w0SCip8zP2#{FPaX1jb$>WmdbyGU zn~ym;D;9d!a!K`RgGDkl;4IF-da~$~X_l3p+{e@8^*-mI`55r5pXH2tSZzrD`bqhF zY-h6MpBap@8$mZf6-+8yprD`i*g|l_yot0UFD@zs==py6(+4eK-zK)vUM}q9`mm+sSV2tJ(Jb+N|9AN?Ct@SR!-2wv?XxUljwi5S}tO zRp#f}Pzd3NVVSxp*Hrm*rOgmI#!`UXwB;2g@q;q9O5yT@pKCU*r{~_dAztZTUQ4dHR>C#es9FESvY*0G8n|YnD9K_)R_EKKn-Y$ zvht~#dBW<{chp;NB|Yp^G0!Ff3$|Ig-+U8pHTkmGVG(MEuq#YTkwWuz#0Ketb$8f9w+y z2QvxNub~9m=YImr!&R=LNK@VuceeSkJpj48m~VS*XlROG!age9UOiA)EBhejUKG=^ zFw>V5{)|3#aML)?Y+6ImW8PTz=b>LesWHXkc!Q|@1CA=Eqv6P)Ef#lZwvqdndFL26_P|o5AS1>KAyQiC>I+BdtDc=EcjS!L5i4`PzscpZKc&Y!Gl<9pa zNFTb~@mL&Cl>A*e#m2);F($|Nuw~ryylnDtAtK4YgC>d9SgR@?mh1k^B}|}^X4NxU zf;`{kWz_OwluL-@>gWB3tPC@Jw|1|CGTrti8r^$I4`j54=`zeZs`dZ{z8zZbAV%Jc zh|UzoSG=@o&@1n))GTJoEo0@qrIMPJGZSbV$G?h4AMW1#BeYovS4lA+bG3zrzMzvrUOTV0u=m(7OB7XG}n_Nh;U<;Ux+vS zx_Y#&5z4vB%T6}Fd)0fyWU$cD!|q_<<$(M%O<^?o`_xg6dN)~q5e_uF1%$%5&daKn zL)(3qmrSlKT#(Xg?PYERH?*71cZzG^!ZJB`LoGrCMu_!KKX&roL{|O2p=ln?e1jDg z+vd?Z?zj7XNGeE`$HMW<1W^%5t!dlO>PAj^n^}I(r%IkqjUfM-X+~4BNgnFLwCsX;^Ru%?V4ITU zDj+qv-FBT_{pQ^G^nG=Z!$jXNkj=)XpYfs=0GB11GP6R5W%G=c; z!QZ?BXvD^uGmeH=P7VcWBiu8-QA3LQFVG|~PxWq>I_?6%k+URNp|zW17TF23*^j1+ zS$cdv63f?{ESugvW^?KWEGu`k0lBh?$u>$~%W~au0ZD;1$Qkx*M@@#9?{^V$+ZGp@ zi5wbW8Jo_XBMxmxC5VFt+4iHZI1kQj{d3=&Wb_*Yat`8emOK=ClmiNzxpU7;amb0s z_L0yi9&WqpdE$BfuW6F0Im_SuVa5vI=}AVSZI?z}m~xk7o24yyM@KWe2`D2UJz<<> zVj|*)aG5yvocttCbpnffymXxuCQ^bP{&4|7T#rV$H(HY&7DyV!_JZsnd{X6s&&lhq zS%VwyF)W_E>lF!MjE)(mehT z>>Ufpi{xi7R1CUKH@?^ZCo2(o{lvDZ{2Z4Hf)oS#1eyT#*I=3XNzyCiY`FPDzkoCQyKr^lUnmZ$cXI5Ye1PK9%wdfSk=&7ctwrx)tC1gojo z6ol-Oxkmlf{&yz3A&ilB{2qf2cf%g69)qz~t>yW8mG&!s`-2@;A3RYQT0J7FPljdy<`vl<&AL9qH@PY8ge+E=*Y zk=YPzZ}&TN9HlPrRu6L-Dve_t?JVn`+MVe)zQ6k6=Yx;@u)jc6x}u>ytBzQ3g3X5T zW<_D*TRm0?PP^XLaG9^HKc>S#b)740!MVMrD9qN)Det-SRlPU<%RutLf%%iyZe}6| z->D3_r%|z5cQh`_M}(s9u>6vlpj~qO@b^O|v2`Z(8{H&_0iEt^mGzjzl0aZ2x=9@3 zS9|1-o7B7TcX6EJfP6{?hh>rgCCnr9jQdR;JMHJE?OfeM2rE@DTPZshOLDJ-zHTqL zwxe(RO{k=HrV{?BV~2;Qz?drP?zLBomuyT>(w>d&tSIhD55iLe|35?+lx+onBlt(J`>hOa+{}ja_stI1I2nu0^nigZy1>j$kt#B*ft#TSh0Q=xLX| zWh<@IWKvr&%kRw*mv#tb$z(xF(3XwHWD}3r1`=9u0Ra;>f1}C)EtRg4<1KqMu|SC* zTJFX3EmR>#l*M%b1Ojf{yh=c%j-EecTpj58;2Xg z@OzESVNjM1eueWxH+l zIOnHo;SH;GC4x5}TLTttQdmlJ=EG07S0@9??{2sQWCz#WUp0Pd;)1L?mtt6>pEa&c zMTTdLha*UF1@4#-FaB9jsWd#n^X(t65z0CB71_6gKiSZsAv$B{`F)6cSXjVcA%%=$ zwqBX?hq*C|qmCmX>zO>3J+USB?QR54|8p!b&!=xKfjFZq&($p1ZhmxmQ`~{cfgg8u zQrtY1ppgJH4PDZYsj~5M4VcT{>LCqOti-Zu06vl{zjsVDe=6ze$KR=tZx{rRl)VIW zAvcHCR0}zEj3y=re%;4g9Z#&snh^{Wnp%6H8?~{hqSM_BWKW2jrvQK6+_J_*f#}9c zJvNi$E?e&RQoCycB3%P=ZvRptwbGnKLh;3%wC!)Buwl^}#Z-m>Q4bgnF z^QaD#a9$@vIQR(WsAe!oO+(-fBSEW(KqT;}w{ow17MV2>!&k&s^L1Wsj7+anq1765 zh@~>*BoOy;IDgLWhV`I*XI_^8F~u>+`zW05x(`9SF1*C34I_b_KNBM0HOH6>;OjPY zxOPUPtuj=W(;|9tO$UR250s`&ZS*Y}%s%x8(sC0LlhW>x2l&0~AN69twM&oNumk#X#12z~d_k!p`o4Cw{nSZPY? z?$~dFuAV^90?^JsWsfs)Na0+6A+W@86+3Gcg;YQ)r~|YcQP;!=u-a9R!vc6YT|9|) z&})1Au&U5Y#jgLNdCS$Asx%fq7={JtrW`~F-$?mK-efMIo;zw-y|2Ytq_cVFlIVTC zE}@-m_6viZ{~SB5n%CWGs0Lp7@EQ%%lB`Y`_Wp%i`zK@7c`9OcpUw0uS&XXhV#BrmWL1@w z*<~F%wdMz$Kh2*y=Gw*-f6Q#)t>;Zs`S}5CFR3i&X1B)8d2=Sa<909EUD(MT&>vWU zv}17o7T8_Rm%#MtK52Jf-FVdi7LQ?UIn9+&Y^MvDSiZYf)h+-IzLPs*T)-0&({J{$ zCqrL9(Fq^MJ(>QI`bjpa4=4GATuW0{@HcoY@kX!1?S{u2){bSv$tNLz88#!6>ch7) z+6VM36DqlqgziL&c&$+W1*!m(<2l3*(m&P!iXKWWC|;qIiP|q-p2>WVVsrtafP3Mh zJ?K@JDcivX=xBMQh<|)OWrytgh-wXIFC|96!K9e15%Uoz}v5f#h+DAJ< z5<8~awD*HX(dZtf#n~N*wN})kgz3`?=fcI~Y`j|PMN=1(u6-;-S}(&&yQ==1u?pmO zvOM_vhkXJbq!+SA{EZ^K$E+H$Um288_(ov_?enE-t;0pY!iDRKckyQelx{(fGt^v; z)PwI!harD(!50_jSw38PwBCOx?IFa7%<6`USCK7ynD}peif!-t;E7t+>`Xz6rFKk; z=k=8904vJ5?YPD+xn0}qDcTc@#Cmeu4$+HYRF`y#)QWCYCxg~g*WzL#G9wi^Epzm$ zxdwl~1UAryez>$8{$=Q>pUFGZ#CmowBKufT69eyPlseV-y$*8&8tzMf9ny~3@t=$S zbosr;X`omN_=lb-2dR4L7lQR4=&|pN^j2LBAgFd3Vh1fA>#av#lt1;2Nkkf&moZim3X~(=4Ru*xP;HY2ZEyuiib;6)0 z$Ik%jFZ7O9wPF7z3kG3P=wZID0qMO}YEiC$>iR394SXp59!wk~YPp6u_XC{*2huP` zv~>E%dA6ct5S*g`x@hl-EEk&XUoE(folgdH=VpU^US39R4Tg3P zWjoDLg>%QqeHXx928Y{KY#?GM^1YJ=`DeC>E=a>i^zP>d^yO&}#m2e1B#N_z2Kvp& zlrn^gS_UsovIF~>bZv|~?NxnXCJ-S%I>b58+laMLz4TX@J$j?dU#PqP*SD3BNX!dD60)_itJ>!R|lMIjrI9s((D26V&~bOR!MTSM8C-TV1IBj zN@{9*<3}Iejkk+MPLri*cDsdX)jn#BU1LI}2Cq>Iosvu+r@0F85oKOfZ`*fwjk{N7 zWz)j#(+u$l1iMfi1(_d%kJ65rx;E#Yo{?!{2X%BqXJY)C<|u#e{%DKMuhN!1CD9WR zQ1+5i%%HY&CMlj>zH_BXk>w$OWbj^ZoaW@4$9xa^piw!^ZY|;+u)x&U#LMk5g*~V`0IYWoSMtdGBP`KJSr#16YQp!j-uM9SVfF z>lYS8my$rg_;!po4i~T(WiC8NgXm8Y&w?-)CeXNy6tN`!aiVe{88Rizwl_+nJ38ui zpF>w97Xkv+IJr9w44`^r2k5SSTZ}`~PTh@SEM11|wL#9!=HA^KqekaHHA=;{#Id(f z=_9}(!Dzl>5?{?RKESB*Hol&MQtz*)Y`c?n;7AlLlomdk_$lhHET?^m`nz?9?;}+ug^gw$?}E1^Ug1zkb1UD7 za0{H`vs(%Z31dXdW(JaTo23q99AoP-+AFpVgpuP~);)f-h9ZP&y+Il8mr%+#g6|hZ zB1;-vmx$ObpIUR_wPy;I*Ri0-;)wCHvmQ}dVCOO@aV96GdGmmLWits;pYPbJ+<33+ zoe^j9%`qO#I-n7^8sKa)gEq(TopO8LH4_CR5Z(Ylhh}~)f5!V-w4cUl<#*_v59?Xd~RMd>Wdtgt}Lm(5q%g+$0TlFHY=!3*;UB#VYzl8!#Ju;c6Wu6r2v! z20GjYp}2_l*#i~UG&_)7ZqEhq_-{GtKHw@8I-c9ACt;(naxYxEH@mbF_9)WC9#nRQ z)uJ+m5WA8A0s*4!Zrpqsvf-rM>}eXscr|u<@wC^IEuV#I?D~v{M1EXYJpd7NX#u=0 zXHeQAJWoep&$tR{TQ&QzncuWVxT|SQT#UBjLy)RTTLlDGtxt%swHFMewAWs>PDI$- z#MOb7<=7^IUF#IOFlD+|w5GTd=q5lWx?_&1xb>oGpL+!#Hai;*?t7qU)QbYwlzIzh zR^7-$@C?9^i8)l?#jvb1e3*PdZp1$>X?-oFjrgrOG!)7=ceJ}=zth3kXZrFcHS z&6gkg?kZQ3XV3d@_7<*^zYCqE!^S834oY*1BP$VJ z`w&;p2Tom|fC81|9Cp#WquNbDZXe;&Ao4{}oLwUz({RLuvGIwEqN~dGJx&E zoLlvype!mK$Ix0sIalF043_l*Y!Hq-$$vh)z{S*TPLfOM41t z%zk!>?-w^{7jveC+yeau7{UG!=2*1|I(oPA6ukYEk59#${t?>uXamQQsJs&s!j@`9bb{qpO1cMX+yl^KTlD^|EgG-dbvE zJkea|VV^+~0EbWfj3*}ALUHEbj@TSfjIQ|DGkp1VwvE@XGHq+6z&ZiWFUNlLebm&` z!WZZxXs&(z2}*cEZluy@RRNAYmpxTCg=~>8d~rHpBaFtD+zqZ`kziUd8>^3%OEqt* zS0}4dG6uU5`&bH!iv_zb2zzOqGNn=$*!(P~KMq(tm$qWQ99NW6@rgVyDPrY>L1z(b z#rd5!9xBbk^)-q`PB=zq$1QmkT19qIi!?M-bvjr{&Yi6aGwycQZag~?oMia0{aG+F z+9(d05Z_l+TZPPL>d^%ADa-L=y`W<8TY95I02x{3bT?h-_gXi%ioI{w%RK3cZFlt zJNs4_<;%Y>b10k}9cNzf-3<>%3wP}I!A|?yMaaK|yG_N1wt5PYv8kgF8*VkS^t5bC z(>y6@4Hcx&w;!i`Up%sAee?IzU~KJXH0ScZQw7W(?zNlJr3aSO_dG1sfibOFSydq` z0lq{gaDSmWmIsuCuB7f-LW^$sQkd&AyMp^JUe*ti^bHrCaGTA~at;9R?JI|n>o0~& zTnBEL<3${BC&f%8cAfQdM@e1g`4|vEunITn>FbVMC-JTkoOn;YKD;~n{?s7*i1o1z z$h$HHQ{EcWq<>&=G@^=d(ni&N!~608S1$k*|I~q)m$2#PczbN~Ig~7m=#PT)dzZv> zx2vT+r~1d_^Ekt9>V~#_es*DvIISBXe*DGN_eq95y%M8Sr&;(>O1TSK^^X>3j|xQK!9F)^)zWiTIUJb?*dbk>lr$pqLxbmaX$7Cfl5fGZF`);BvvU3QzK#U znmJ=Q)Qr}z%!Y|fvkSRZ0J*-PDjw1@C*UwudmFbOy^0cSmI%G#-e1~Gd*D}1Y>PAZ ztvRq{D=BY;A)IXHThhv!*d_GELSvv{&!2>VEv*x)NlJ=R)cuPuP={GO19u(1$#K+6 z)BeIId24{iwa9uF`HYu<|MZ2qO5fS?gGC$WLJf;7-42j&1+9~b`YUfSRI_!-S6QFh6j*HR= zN?O70n$eT^RYw@1A#l9*9gByqDkFPgj>kNByU95`t(tZDoUXA1opy697$u?1@iQjv zcgp4fjWDVU-;1#*IhJsx+GpGdM4MR;J`V)e?3yFNPYJZ>yvx*T zU1Cz{9(nS~7z8bz@!pOtJD28qJ;6lv$8a$r4;9q49ffhrs&^>La$=>ssBeQnMNYdV z3+%Id)!#r5Xa&UUF|9N?9hS?P!-KQ%Ckk4QPp>TZF3#)NEcafb(^iOn1rHxYD2e8u zNVCoHXj8zc4=Be##Ap>@*$rJn*#e? z8#al(CtNf?yI5&U&Mgqf0)Nb+`uS|Q>Sw@_U+o5!qOCH*P?ykNmV91@PNHoGo}O=C-I+X_dMVCUyJfL^_<|3F#jl1%h|2c42osa=U2vOao*=JwgfZx;71Zjb?~ z7M^IZ4**(EvjWXfxxiQlXh=H&Got@vi85Q5H9zyBP!Q|<9N@=O=v=L%)I61ZhvZj3 zS2lcE8px{7bhYt^(U}&l&OCHWK{FfcebP{HPLINgs9ni+zwa4)#1rqd z&mgTl2fJXBt)ivwu}tor+L_TjHWa~})v1f43atm%qr@L~@CEGBQ9Bi^Pc<<4?d1RT z^69Q#FK70>G&|n5Kcb4@GB0ft#F;frgGynA^9V#O&H4XLSQ?u;l!w5KqKG1=H<&o7 zXl7f~W;3d|BQzA#@OKXosqU}&#WKTqDSA#J;@A#2F$V4VU6OM{2<`3eOBO%fhdcQL!UqihK*ObeQ1>?_Y<#&i=|W5#XV-f)AZR5{*}qm3I(XR>SXvTw=8ZQfj?idsTTSCq zS)6qvyqvQ8&41B({&1bd|LAY?MnK$&)YAb8iYRL#y^hg5Tm|C^I%R= zZ7o;LAp8jNS3u&i$cv)Kb9@|ljX^O_@B1)qkt6=Jj?5br#=#O#I<4G`T4*Ojk!68_ z(A<0=kS3Rm3~2~gr2{8)z+PG4;>U-T|o>Whj} z37r@bb_jyHZ!U+^K5pRq$oH?cItZ`*2U#$27y;>S=W4c)OIl?*Z7-N} zaJ_Eke|}Fm_~65Y@!GBT{7*risZF3(5)`hP29!d$?!H-4%JTlh)DzGEvL%b_ABTkO z3{igJjeN8i)IusbXF)Duf5w}a^JI5)odY_ z5h73(%ihDn`~M7Bfvj{vW=NJ~4Wzk9{AV(WOG@Ao@@zIv8rW_3UjC061pk>nqqe4_ zt%UT|Er4hk%92bVcS3=^6Br7~+%CX(Nm(C&`sDiB|4&T1*IUxUYH&5d&&b2WCd*M+ zZ22SS2VCAb%-jBKb#t@!XyOht;CUoL=7lXARMdda${K3)zSp$ZlI0Z@rX4|*E=~&- z^Xu~sZrQ%>>et6bYR^R=Zq-I{|5VTd;}#|$#f{-AEcGJ%lHcG$fu$t(jVfM2!OT*b zgCL%=*Q)2i|6w{69hRHEmTRpWUoW?rIhYHk{bd=)bUEW}xlX@PqaTiPJY$d_2nPx- zkItDjNwi?H_>!0?a%xdAYavMko3W* z5Mgy-aoj-*4@Hkw{mJ(Oq5Xc5s6j}i^>np@9%uZsZT-CT5EE6VH8MDtfj+%*0}08+ zJ#iFNbVpY4G(Ne@Zbhp2)aLW@EgQQbRh&SVnY=Tpx*0LnrcAX!4F}6G6f|r)a5xH7 z*SP*$&=YXDc+mpa?&UeeV{1=w&z&{G;^Zv>LHF_~zbJ=+-Y&UFLmUArIl`%;KBW~s>j0Cx$RsmGBsxB8n0_n7Mj6(sFgE-9C z>qVmSx^xM69tX=gUkR+$R41-yTI%eyS3w6?M(h0H9isj<5h5%N6h-re-*+!^%i5|> zl_k(&W^wt8-ldr~CNo-~ilJr5EwZuzWYISyOVcYKqGe}i@6RsWDAGW-KDm#Zkf_xt zvol>8qn=%Qrse^?M35^>LqW%enU%%x@md3=6B<^kYJT?{v7GsC?ljLj8oRga8uH#) z$r0QVO`eoa*~)Tg%oaV=U@^B><>Fk(PEO59ZjawJkSr2oZKb@v&+Y|xO*`{c1adKc z;yW0~!HMQ36SJwMIv0SkEV|$M{5&j@u(79;uPP?oscpTpiQDr5hRvo$@>J zWGRh%;$Q`|=1oh4VvBJ%ZTvUg1IKYrDPu<~6V-Yz8HPAI(%Em#!rl*Wv8w`LS7)_& zZ?d;%><7H6#+NfTRs$0rsH+K`cDB`ps5}V$St1y-hM8|gj_ zi7-b9xte&^`wRMb8mbf%gv%{VRWf|(@z3KYl|phBx0;`L5$I~ivChQq;$&rf(jaEu z>m)a^DmEXs{N920^V_%fq73AA1U*0d8|&$wz@Z=mo>1hJ#J`k*IfMMDB2myhxQ3@- z4DW|T=#^ZOKc5pE;R6BM*S;9u3mo*^%v_=)GB z6*ai_j18s4-v6Qawy0ODfI0SoTC1y09Ama>X`rz~orjmCr*w`sOkj+Qpqm~kcmhno ztj{)`B?gK(HeEB^rfJqL}ggOi*g zn?#G^D6Jm04*9G8EJ$tF_gf7^cY$OGJ9!*zx@cN7&+<h?^132Pd=ybJ zQG7BB%%Qi;^GgpHa5d;VDk?gzoH&+slW6McIQ~14oi|ZZho=l8Om)8A%SRh9o0kfb zw$&?+Z;kdoethEA&0wiVGFEcr&d{V3CHrJEJ)qM1mc-Z(G5|eCb)p+m-}z=OaJ0f& zgeFQoH&_P4>yp*2F{vRAbW<5@ml$LOD^$yV0~Q5PyOsFF+$Svqhdbgqg{ z4&;u`^#pN|q@!yAD7UKRt4xVbY_BQ4aHf^c6tn*9S4}sAr?o1JZO!c4+3MfAHnTMb zd{xy&C-%wK3SWBQLVrGI)rWD3kd<{Yu{J?zV(hgR>OBOBZ--Pu4k;^RQb3Wt>5s^( z@nO-Za$zO6-7$lk6+pg|-?2>a<7oAY5>CjeOyX9<5w~Ku;H{uuD}i@=IHx^o)ecWT z-fbVK=v!zkN11KzuZ|~%N zf{FNBYRpcQXmqRc%?#nn*e(7FNX&(fKUU_8+epQ_X{4^by2EM$6LHu_)6-4TvvXQs zp8O4I3`>{IfL*ubn4*RgSr5}#6>0_JJ8h+1)Cv>tqH5?{QP3L4m2iSKIg71~GMZ&7KPrvsh&qB>o66TNOw>T(YHM>i3d z;vHUI@I2aVW=OAlbdj_rajQMF)0)e4bcG^&CS;CHy*U+;911A$XSnM<^pN<$K6PKE zXMA>@e2++TH5@GV&JkIEI^)&P1B%!({$k##1SY)oz@KOxpfAd7pDG?B2N3o~P2Nw- z{*$}4BYgH(Y4Fh*r|A|1$md^}ia)k~|3M5l78Y_Z(jCs%Eo zEv(+R8)(`ThH6h%zd|HX9^^(=vO+==pX-?L2Lup59w>>+kJJ=}hKo~{yx*nIJ{+Zi z|53pzU<; z!=A}s{8pIc3}`CPbc+Bpv}S^&th2>?v1m)?X3Wdxcf*IugHH?Cp8rkdiqPZf_$6MX z|E93$Kz6#>PK>RHY+8(G;1;dgsp8LR;&rOrwNGSd-?;k>)*2K~{^(LcQt=$4cMe{j zXZmAHWSX(Lo&X_sPv%Y^E5AnbOb&l%;LU2h;9aCzCI$3pDzFOu4AoVr$TN+PZS~Fc z~Hn`1WU& zGH-Fj4mCHIW%9JuwIDKDB4)kiWkQ^<`HR+7Z=u6Js~&rH)12pa|8SZ7gW(t%vu+u9 z*AL(L#Io5hZyDrGh>by2^)*eKWc1X9HZSe9d&k?2F8ys*Zcrkm0XV`*wKX{=Ywjx$ z9T%8frS|pzDlH>>K?MN#E7q@|QIC&r_p6AKFo(vqC!2O(ErV8*MBVK&6!F%dg*0b! z)mJ{{zc~t#KZekk*-vd)t|)j&V_CXzox)fP6fT5Jf<0^JY*jpnv8PrCCSyWxwXlht z_>EDrdW)(O(NRy@TbLN{a8gl*0N1UcfzaQ=9==whv)Eo&kCEL$x01u26!nX!xkU)B zo_Lh3b2MKgH`i7CP@hd~5XZeRQul)A1nDR-pc-pxp|| zt58Yu;hr;c|1nL`nT^V~GJXw0^5^Cb+u8N0+OkpKfkNf4$thCtu+@_Wbjn-<(f#RaVJkqEV zX<_|T-dWAH5{{C?{FBikPt4+m41bfGli9sHz}L{uCmurzl;t@HbI38q!ajDkZ{EYz z85+rE3}NSdW9~Ci|L{4lgzunGC@zvZM8x)aWkEDiS>24|CtZ&%<&7c~VD4Fx1GO#% z!LiNTsB3?0?&J|@dB8H^oHBi={W?k}jv>E`*)u%D00FQ?hmsf~gx>lD*d~5goK6&| z#xm#kzvn!EB0E$)PDK4(;bvQ9w{Bd1Zq$ytgZ2*Q6-~NiH%%_$xKH^q>_#HpHz#i4 zvmuVN5?=x93cFAixpQqg&Qpf1JB09x?#(^Q{94dMU(A~vLv(B0&_&xo)md3&d7;2+ zmM3agc1{_tzRUlVQhIJ!fk&KMl~js#yD$Cc!(JV*05j(v+!6kk`v3Nr0<7v8g{gpl z`|_5PZyy4HZ#AJ}i~H(UFZ}0Y3ou=_neKG{t=ahR4=TXQM?B>Zyw%?Sd({8>-`R0|MeP)OPuTSHL3khzx?~q$nP2e2c-eW>wo%L27v8luY%!!8}(nWe(wR) z%zqU5*ZY4%fnO#78#O$K`;H_2W0F=*05!JlH2>4jNJk>lQSIT~X7(SGfXM*|h~JRt zfB1PZ7l2Ksjs^ceNqUQi(*IBP|Deb}?D>Bs`(jHhtm9!1OOq|oiX25&O7V5EB-sCd E0nk;cf&c&j 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 510126bc9d71079fc891694f566d0e28f2a34b83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37919 zcmeFYWmr|;);A1@N~oY)x68ZPZjc5k=?)R;Zb|9x?q_ZAf6jUD z=YBswU(UX+b?vp*UTe-V#~kq+v4cL!h`vO^MuLHXc_}U?EC&Pg6dMKxmJ;C^aK{C8 zCl&_gg}I54&_{70A;OQgRz@b~hA=Q^}*AP{lz0l6gc%`gObcsOi`p zvfg4maFaKi=(-Q{^>=TqSotR!7~6K|k*V*5YZohT$u=nn;iUOtOIl-lqs3Ji7$RYM zbnYFUJwb$D?vk>+x6_yJ740tIuuxzOh}%uvu;`vIJ%c%r<_=;;fyorKVxW=DY&|BN zh;4%*(kg7ll4un58jY#-XeHx~duhW2W2!)_oCN#1!#&@4?U<1;yu&y!^_N>DCQScp z)azqk4c_)IQ=%&?Qi^}%0xdF{;Po(34kWI_n3k<>OoVPUEIUw@)>sHle-I~$n9^}@Var~(XDsdHi^cNNXuj?7!Yo0ztA8I3LMh{ImxM2mV2|x*-5gVi zrK{xB>@g}h!KfX9Z9&pTSye@(M!Uz!_?)%W$&BQCD2^&mSlx&5PDG#xwk(>OidN8& zsh+0$sKA`z7ImgA8t6x7u>vDJ*

JFa%AnKVdTZgj|O!<g>#RluUhYt` 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 R@Q>2&$Vn+nmWUhr|1Sc_55@oh 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