fprime/Svc/FrameAccumulator/test/ut/detectors/FprimeFrameDetectorTestMain.cpp
Thomas Boyer-Chammard d0246f148b
Add Framer FPP interface, implement FprimeFramer and adapt ComQueue (#3486)
* Initial FprimeFramer and FprimePacketizer

* Code clarity + set up UTs

* Rework ComQueue and ComStub to use DataWithContext

* Add packets to RefPackets.fppi

* Fix ComQueue tests

* Add hotfix to FileDownlink instead of ComQueue

* Fix cancelPacket as well

* Fix ComQueue UTs by removing hotfix

* Refactor DataWithContext to use an FPP object for context instead of Fw.Buffer

* Touch up testing

* Add docs

* more docs

* More docs

* Rework buffer deallocation pattern to pass-through ComQueue

* Update ComStub UTs

* Restore original FileDownlink.cpp

* Formatting tweak

* Update deprecated getSerializeRepr() calls

* deserialization methods

* Fix spelling

* add cast for safety

* CMakefile change

* Bump ComQueue depth

* Update RPI deployment with new Downlink stack

* Rename comQueueIn port to comPktQueueIn

* Fix comQueueIn to comPktQueueIn change

* Remove legacy Svc.Framer

* Fix CMake UTs

* Fix RPI topology config

* Fix FprimeProtocol.fpp module

* Fix namespacing

* Use const reference for FrameContext port

* Review comments EXCEPT port passback refactor

* Rework ComStub with new ByteStream

* New ByteStream - ComInterface model

* Rework TcpClient / TcpServer with new bytestream

* Adapt UDP component for new ByteStream

* Adapt FrameAccumulator for new ByteStream

* Adapt FprimeFramer for new ByteStream

* Update Ref topology with new ByteStream model

* Remove all legacy deallocates from Drivers; reintroduce DEPRECATED model types

* Fix spelling and include error

* More spelling....

* RPI and RpiDemo fixes

* Fix conversion warning on RPI

* static_cast for short int on RPI

* Standardize port names

* Remove legacy Drv types and merge RECV/SEND enum type, delete StreamCrossover

* Update SDDs

* Update SDDs

* Fix ComInterface <-> Framer interfaction, clarify comments and fix annotations

* Switch ComStub from ASSERT to log failure and return buffer

* Add history size check + clarify test handler overrides

* Fix RPI topology to wire comStub on Uplink

* Rename comm to comDriver in RPI topology

* Update communication adapter interface docs
2025-04-29 16:40:36 -07:00

166 lines
7.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ======================================================================
// \title FprimeFrameDetectorTestMain.cpp
// \author thomas-bc
// \brief cpp file for FrameAccumulator component test main function
// ======================================================================
#include "STest/Random/Random.hpp"
#include "Svc/FrameAccumulator/FrameDetector/FprimeFrameDetector.hpp"
#include "Utils/Hash/Hash.hpp"
#include "gtest/gtest.h"
constexpr U32 CIRCULAR_BUFFER_TEST_SIZE = 2048;
//! \brief Create an F´ frame and serialize it into the supplied circular buffer
//! \param circular_buffer The circular buffer to serialize the frame into
//! \note The frame is generated with random data of random size
//! \return The size of the generated frame
FwSizeType generate_random_fprime_frame(Types::CircularBuffer& circular_buffer) {
constexpr FwSizeType FRAME_HEADER_SIZE = 8;
constexpr FwSizeType FRAME_FOOTER_SIZE = 4;
// Generate random packet size (1-1024 bytes; because 0 would trigger undefined behavior warnings)
// 1024 is max length as per FrameAccumulator/FrameDetector/FprimeFrameDetector @ LengthToken::MaximumLength
U32 packet_size = STest::Random::lowerUpper(1, 1024);
U8 packet_data[packet_size];
// Generate random packet_data of random size
for (FwSizeType i = 0; i < packet_size; i++) {
packet_data[i] = static_cast<U8>(STest::Random::lowerUpper(0, 255));
}
// Frame header | Start Word 4 bytes | Length (4 bytes) |
U8 frame_header[FRAME_HEADER_SIZE] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00, 0x00};
// Serialize actual packet size into header
for (FwSizeType i = 0; i < 4; i++) {
frame_header[i + 4] = static_cast<U8>(packet_size >> (8 * (3 - i)));
}
// Calculate CRC on header + packet_data
Utils::Hash crc_calculator;
Utils::HashBuffer crc_result;
crc_calculator.update(frame_header, FRAME_HEADER_SIZE);
crc_calculator.update(packet_data, packet_size);
crc_calculator.final(crc_result);
// printf("crc: %08X\n", crc);
// Concatenate all packet_data to create the full frame (byte array)
FwSizeType fprime_frame_size = FRAME_HEADER_SIZE + packet_size + FRAME_FOOTER_SIZE;
U8 fprime_frame[fprime_frame_size];
// Copy header, packet_data, and CRC into the full frame
for (FwSizeType i = 0; i < static_cast<FwSizeType>(FRAME_HEADER_SIZE); i++) {
fprime_frame[i] = frame_header[i];
}
for (FwSizeType i = 0; i < static_cast<FwSizeType>(packet_size); i++) {
fprime_frame[i + FRAME_HEADER_SIZE] = packet_data[i];
}
for (FwSizeType i = 0; i < static_cast<FwSizeType>(FRAME_FOOTER_SIZE); i++) {
// crc is a U32; unpack into 4 bytes (shift by 24->-16->8->0 bits, mask with 0xFF)
fprime_frame[i + FRAME_HEADER_SIZE + static_cast<FwSizeType>(packet_size)] =
static_cast<U8>((crc_result.asBigEndianU32() >> (8 * (3 - i))) & 0xFF);
}
// Serialize frame into circular buffer
circular_buffer.serialize(fprime_frame, fprime_frame_size);
// Uncomment for debugging
// printf("Serialized %llu bytes:\n", fprime_frame_size);
// for (FwSizeType i = 0; i < static_cast<FwSizeType>(fprime_frame_size); i++) {
// printf("%02X ", fprime_frame[i]);
// }
return fprime_frame_size;
}
TEST(FprimeFrameDetector, TestBufferTooSmall) {
Svc::FrameDetectors::FprimeFrameDetector fprime_detector;
U8 buffer[CIRCULAR_BUFFER_TEST_SIZE];
::memset(buffer, 0, CIRCULAR_BUFFER_TEST_SIZE);
Types::CircularBuffer circular_buffer(buffer, CIRCULAR_BUFFER_TEST_SIZE);
// Anything smaller than the size of header + trailer is invalid
U32 minimum_valid_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);
Svc::FrameDetector::Status status;
FwSizeType size_out = 0;
status = fprime_detector.detect(circular_buffer, size_out);
// Expect that the detector reports that more data is needed
EXPECT_EQ(status, Svc::FrameDetector::Status::MORE_DATA_NEEDED);
EXPECT_EQ(size_out, minimum_valid_size);
}
TEST(FprimeFrameDetector, TestFrameDetected) {
Svc::FrameDetectors::FprimeFrameDetector fprime_detector;
U8 buffer[CIRCULAR_BUFFER_TEST_SIZE];
::memset(buffer, 0, CIRCULAR_BUFFER_TEST_SIZE);
Types::CircularBuffer circular_buffer(buffer, CIRCULAR_BUFFER_TEST_SIZE);
FwSizeType frame_size = generate_random_fprime_frame(circular_buffer);
Svc::FrameDetector::Status status;
FwSizeType size_out = 0;
status = fprime_detector.detect(circular_buffer, size_out);
EXPECT_EQ(status, Svc::FrameDetector::Status::FRAME_DETECTED);
EXPECT_EQ(size_out, frame_size);
}
TEST(FprimeFrameDetector, TestManyFrameDetected) {
U32 MAX_ITERS = 1000;
Svc::FrameDetectors::FprimeFrameDetector fprime_detector;
U8 buffer[CIRCULAR_BUFFER_TEST_SIZE];
::memset(buffer, 0, CIRCULAR_BUFFER_TEST_SIZE);
Types::CircularBuffer circular_buffer(buffer, CIRCULAR_BUFFER_TEST_SIZE);
for (U32 i = 0; i < MAX_ITERS; i++) {
FwSizeType frame_size = generate_random_fprime_frame(circular_buffer);
Svc::FrameDetector::Status status;
FwSizeType size_out = 0;
status = fprime_detector.detect(circular_buffer, size_out);
EXPECT_EQ(status, Svc::FrameDetector::Status::FRAME_DETECTED);
EXPECT_EQ(size_out, frame_size);
circular_buffer.rotate(size_out); // clear up used data
}
}
TEST(FprimeFrameDetector, TestNoFrameDetected) {
Svc::FrameDetectors::FprimeFrameDetector fprime_detector;
U8 buffer[CIRCULAR_BUFFER_TEST_SIZE];
::memset(buffer, 0, CIRCULAR_BUFFER_TEST_SIZE);
Types::CircularBuffer circular_buffer(buffer, CIRCULAR_BUFFER_TEST_SIZE);
(void)generate_random_fprime_frame(circular_buffer);
// Remove 1 byte from the beginning of the frame, making it invalid
circular_buffer.rotate(1);
Svc::FrameDetector::Status status;
FwSizeType unused = 0;
status = fprime_detector.detect(circular_buffer, unused);
EXPECT_EQ(status, Svc::FrameDetector::Status::NO_FRAME_DETECTED);
}
TEST(FprimeFrameDetector, TestMoreDataNeeded) {
Svc::FrameDetectors::FprimeFrameDetector fprime_detector;
U8 buffer[CIRCULAR_BUFFER_TEST_SIZE];
::memset(buffer, 0, CIRCULAR_BUFFER_TEST_SIZE);
Types::CircularBuffer circular_buffer(buffer, CIRCULAR_BUFFER_TEST_SIZE);
(void)generate_random_fprime_frame(circular_buffer);
circular_buffer.m_allocated_size--; // Remove 1 byte from the end of the frame to trigger "more data needed"
Svc::FrameDetector::Status status;
FwSizeType unused = 0;
status = fprime_detector.detect(circular_buffer, unused);
EXPECT_EQ(status, Svc::FrameDetector::Status::MORE_DATA_NEEDED);
}
int main(int argc, char** argv) {
STest::Random::seed();
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}