mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 00:44:37 -06:00
* 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
166 lines
7.0 KiB
C++
166 lines
7.0 KiB
C++
// ======================================================================
|
||
// \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();
|
||
}
|